@qwen-code/qwen-code 0.21.12 → 0.21.14-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/qc-helper/docs/configuration/settings.md +13 -5
- package/bundled/qc-helper/docs/features/code-review.md +18 -13
- package/bundled/qc-helper/docs/features/commands.md +120 -8
- package/bundled/qc-helper/docs/features/sub-agents.md +2 -2
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +20 -3
- package/bundled/review/SKILL.md +130 -82
- package/chunks/{MaxSizedBox-ZSJJ2D5S.js → MaxSizedBox-3PZITE2Y.js} +46 -45
- package/chunks/{StandaloneSessionPicker-WHUHQXSA.js → StandaloneSessionPicker-2C34PNGO.js} +68 -67
- package/chunks/{acp-startup-profiler-SVPUHLXV.js → acp-startup-profiler-HUYGO57H.js} +2 -2
- package/chunks/{acpAgent-7JOAESF5.js → acpAgent-3J4NHAYT.js} +1098 -366
- package/chunks/{agent-E6V3VXQR.js → agent-VFX4RPP5.js} +42 -41
- package/chunks/agent-headless-6WCF4J6N.js +88 -0
- package/chunks/{anthropicContentGenerator-YDT4EOKO.js → anthropicContentGenerator-M7XRJMSK.js} +8 -8
- package/chunks/{artifact-tool-4GCQQDZI.js → artifact-tool-GEXTOPVO.js} +2 -2
- package/chunks/{askUserQuestion-HZJJLR3Z.js → askUserQuestion-B33XRSB7.js} +2 -2
- package/chunks/{bridge-NPBV53UA.js → bridge-XR5ZSR7U.js} +46 -45
- package/chunks/{ca-4CQ6MYNQ.js → ca-SLZJD6QH.js} +8 -0
- package/chunks/{channel-management-service-OADNGQM3.js → channel-management-service-X6LCQUAD.js} +1 -1
- package/chunks/{channel-settings-store-4ODLJ4X2.js → channel-settings-store-Z7BUEUJE.js} +50 -49
- package/chunks/{channel-worker-group-IHBIHQ45.js → channel-worker-group-TJ35JDPE.js} +4 -4
- package/chunks/{channel-worker-manager-GEHYJ5AE.js → channel-worker-manager-G5LKWGOG.js} +4 -4
- package/chunks/{channel-worker-supervisor-ZJIIWM4I.js → channel-worker-supervisor-OEVWBHGT.js} +2 -2
- package/chunks/{chunk-47BGDLJG.js → chunk-25GHLMQQ.js} +42 -20
- package/chunks/{chunk-2ZWH53I4.js → chunk-2B2BF7P7.js} +3 -3
- package/chunks/chunk-2C6HJMG3.js +757 -0
- package/chunks/{chunk-WM3LUQLO.js → chunk-2JXDFSVE.js} +6 -6
- package/chunks/{chunk-OYWVIXHT.js → chunk-2M55OBEB.js} +1 -1
- package/chunks/{chunk-B4VN3VDH.js → chunk-2OA3JMRD.js} +5 -5
- package/chunks/{chunk-GZDWTBT3.js → chunk-3EZLLVDF.js} +2 -2
- package/chunks/chunk-3PWCMXIR.js +9169 -0
- package/chunks/{chunk-XAFIL4BD.js → chunk-4KQ2TI2K.js} +5 -5
- package/chunks/{chunk-OPVF453Q.js → chunk-4V4DFJBS.js} +3 -3
- package/chunks/{chunk-DPTMKFIH.js → chunk-4ZMS3JCR.js} +43 -12
- package/chunks/{chunk-6JEIRPLN.js → chunk-55PIFSP2.js} +2 -2
- package/chunks/{chunk-V6OBVAST.js → chunk-57KOJ2KZ.js} +1 -1
- package/chunks/{chunk-QLTATTPS.js → chunk-5CVO7YES.js} +1 -1
- package/chunks/{chunk-OK47XBYH.js → chunk-5IYS4WWR.js} +1 -1
- package/chunks/chunk-5MK45KZ3.js +492 -0
- package/chunks/{chunk-OWXFBIB6.js → chunk-6DFPR7CS.js} +1 -1
- package/chunks/{chunk-YIGGWOJE.js → chunk-6HY6IF3Z.js} +1 -1
- package/chunks/{chunk-XDRXOSAD.js → chunk-6LAPGPVA.js} +7 -5
- package/chunks/{chunk-Q4ZPYNIZ.js → chunk-6PDOHRN6.js} +4 -4
- package/chunks/{chunk-OWGRUU7F.js → chunk-6QFDQMQX.js} +1 -1
- package/chunks/{chunk-MUNA4QDC.js → chunk-6VDPDHIP.js} +29 -8
- package/chunks/{chunk-MDNUCDKZ.js → chunk-73G3Z7QS.js} +3 -3
- package/chunks/{chunk-VIFA5VJD.js → chunk-7OCSX7FC.js} +1 -1
- package/chunks/{chunk-D2RNVVH6.js → chunk-AKBOLMUF.js} +96 -18
- package/chunks/{chunk-S6TCTH4Z.js → chunk-AQBHJ2IG.js} +12 -12
- package/chunks/{chunk-WCEI6J56.js → chunk-BOJNAPUE.js} +2 -2
- package/chunks/{chunk-DAV4QFD5.js → chunk-BQWNIPTE.js} +44 -3
- package/chunks/{chunk-HOSVOUDK.js → chunk-BUQDLC2G.js} +3 -0
- package/chunks/{chunk-LUISTZXI.js → chunk-CH5OFRV7.js} +2 -2
- package/chunks/{chunk-G6MUFRNI.js → chunk-CHHABXPE.js} +1 -1
- package/chunks/{chunk-4AOVQPJU.js → chunk-CPHEPGAO.js} +1 -1
- package/chunks/{chunk-MS7GNABG.js → chunk-CXJHQVEK.js} +8 -0
- package/chunks/{chunk-K5IDV3PC.js → chunk-D34RDOLP.js} +12 -2
- package/chunks/{chunk-3GM5DLBI.js → chunk-DGJ7O55J.js} +3 -3
- package/chunks/{chunk-7KJPO7YH.js → chunk-DRKYT2TR.js} +2 -2
- package/chunks/{chunk-PZW46OTB.js → chunk-DVR7XKO5.js} +2 -2
- package/chunks/{chunk-CQ6IPDQW.js → chunk-DZCV3ZYU.js} +3 -3
- package/chunks/{chunk-ULNWG62W.js → chunk-E3DYKPYZ.js} +3 -3
- package/chunks/{chunk-YCHNAKC5.js → chunk-E5RS7LF4.js} +44 -13
- package/chunks/{chunk-4NFY2S7N.js → chunk-E7REAOTN.js} +15 -0
- package/chunks/chunk-EOCQCNV4.js +3887 -0
- package/chunks/{chunk-D7QGE3RT.js → chunk-FAAUPSY2.js} +1 -1
- package/chunks/{chunk-2IVYL3IF.js → chunk-FCTLOVYW.js} +1 -1
- package/chunks/{chunk-QPBFRWCP.js → chunk-FS5NGKWC.js} +3 -3
- package/chunks/{chunk-RQJA2YYO.js → chunk-G6FFFICU.js} +4 -4
- package/chunks/{chunk-36XKGB7E.js → chunk-GV3OIADZ.js} +3 -3
- package/chunks/{chunk-3AEKDXKT.js → chunk-H4A72DE5.js} +1 -1
- package/chunks/{chunk-IH4Z54RJ.js → chunk-HGPMOXLZ.js} +5 -5
- package/chunks/{chunk-DG4IQ6JG.js → chunk-I3N2Z25H.js} +3 -3
- package/chunks/{chunk-WI6GIM2M.js → chunk-I7NTHW4C.js} +2 -2
- package/chunks/{chunk-ZBB5EZZV.js → chunk-IA2K2HJE.js} +2 -2
- package/chunks/{chunk-IRSLAS4M.js → chunk-IOTPI425.js} +19 -11
- package/chunks/{chunk-ROIJYS5K.js → chunk-ISRHAMNL.js} +3 -3
- package/chunks/{chunk-CGM3E75C.js → chunk-J63PKMYA.js} +3 -3
- package/chunks/{chunk-PTSEETCO.js → chunk-J6YS7Z25.js} +107 -13
- package/chunks/{chunk-ZQUY3ZJU.js → chunk-K3CECR5C.js} +4 -4
- package/chunks/{chunk-QBJYSIQ4.js → chunk-K3LPAED5.js} +53 -12
- package/chunks/{chunk-FRHQQC2Z.js → chunk-KBXKR5R2.js} +1 -1
- package/chunks/{chunk-4KM2SYK5.js → chunk-KC4WMLZO.js} +1491 -10579
- package/chunks/{chunk-IX4PWUDU.js → chunk-KSGWAYNE.js} +14350 -8679
- package/chunks/{chunk-CPFFU46D.js → chunk-KV27IEHM.js} +1 -1
- package/chunks/{chunk-OR64CU46.js → chunk-L6CCLB3G.js} +1 -1
- package/chunks/{chunk-M6NDLY2T.js → chunk-LD5VIJ7S.js} +1 -1
- package/chunks/{chunk-GXTMEATA.js → chunk-LLR424CQ.js} +18 -15
- package/chunks/{chunk-RDVNSJQU.js → chunk-LRDB2OLB.js} +3 -3
- package/chunks/{chunk-LSRI3ND3.js → chunk-MA2HEDVP.js} +1 -1
- package/chunks/{chunk-DFVXU5YM.js → chunk-MCG53LWC.js} +1 -1
- package/chunks/{chunk-YBVVOSOH.js → chunk-MIPFDQAF.js} +1 -1
- package/chunks/{chunk-KRXPRVGL.js → chunk-MLXTMF7H.js} +0 -1
- package/chunks/{chunk-BSR5AXZR.js → chunk-NRPXRNN4.js} +1 -1
- package/chunks/{chunk-X5SLJOMF.js → chunk-NV6LW6FT.js} +4 -4
- package/chunks/{chunk-YILJKX2T.js → chunk-NVRMCWTP.js} +10 -6
- package/chunks/chunk-NYWWQ437.js +24 -0
- package/chunks/{chunk-AKBFSOC5.js → chunk-OBJYN4MX.js} +2 -2
- package/chunks/{chunk-NX4A23LY.js → chunk-OJOP26ET.js} +3 -3
- package/chunks/{chunk-3GDBZJD6.js → chunk-OLZSWUZR.js} +7 -7
- package/chunks/{chunk-K34GJQOZ.js → chunk-OO4FKHLO.js} +4 -4
- package/chunks/{chunk-BSSLSQEW.js → chunk-OSAFWBNR.js} +3 -3
- package/chunks/{chunk-TMFWI4RC.js → chunk-OVY67CYC.js} +1 -1
- package/chunks/{chunk-6ZKSO6K7.js → chunk-P425IVUK.js} +7 -7
- package/chunks/{chunk-4XA4QIUA.js → chunk-PMS7O6SA.js} +1 -1
- package/chunks/{chunk-LCX5B364.js → chunk-PPTM4O4R.js} +3 -3
- package/chunks/{chunk-VPV7WBVT.js → chunk-PT4I7NBA.js} +1 -1
- package/chunks/{chunk-3LDGOQXZ.js → chunk-QECSDJET.js} +6 -6
- package/chunks/{chunk-FMIH5KMQ.js → chunk-QEJZUXSK.js} +1 -1
- package/chunks/{chunk-NLFLYSS4.js → chunk-QFJ5JHQR.js} +1 -1
- package/chunks/{chunk-KWX56CHZ.js → chunk-QIHHJKXT.js} +7 -7
- package/chunks/{chunk-TDESMS7M.js → chunk-RAQBBGS6.js} +50 -70
- package/chunks/{chunk-KEC5FHLM.js → chunk-ROIYNTHJ.js} +3 -3
- package/chunks/{chunk-63FNZTWG.js → chunk-RWDNJBWN.js} +2 -2
- package/chunks/{chunk-56HVDG3M.js → chunk-RXHBTKMG.js} +6 -6
- package/chunks/{chunk-MAKIANMX.js → chunk-S6CXQKDD.js} +3 -3
- package/chunks/{chunk-CIDQISGM.js → chunk-SA7GBPEA.js} +5 -5
- package/chunks/{chunk-YX2RDGAL.js → chunk-SBRIBTYN.js} +1 -1
- package/chunks/{chunk-TTRH3RTQ.js → chunk-SG7ZP5PG.js} +4 -4
- package/chunks/{chunk-XH3KAV2G.js → chunk-SGLPDKRT.js} +3 -3
- package/chunks/{chunk-JRIVMPD2.js → chunk-SLILKYV2.js} +4 -4
- package/chunks/{chunk-NW2GIPG3.js → chunk-SNQZZ765.js} +2 -2
- package/chunks/{chunk-I7BT2MME.js → chunk-SR2LYSMT.js} +1 -1
- package/chunks/{chunk-TXP5NGG3.js → chunk-SXCOEJO4.js} +1 -1
- package/chunks/{chunk-MELQSJOU.js → chunk-TNPWODIZ.js} +1 -1
- package/chunks/{chunk-VLHR7F4E.js → chunk-U6RZRKNM.js} +247 -198
- package/chunks/{chunk-HTYND72J.js → chunk-UC67T4SF.js} +3 -1
- package/chunks/{chunk-HG3UBTJ4.js → chunk-UYDGFWIJ.js} +609 -23
- package/chunks/{chunk-6P5EXEBL.js → chunk-VGAAAMRD.js} +1126 -232
- package/chunks/{chunk-WDVDVWJ3.js → chunk-VHPMDDPT.js} +6 -6
- package/chunks/{chunk-H7TMVHKE.js → chunk-WGHHA7ZH.js} +1 -1
- package/chunks/{chunk-FQDCO3CJ.js → chunk-WP4WIUOJ.js} +7 -0
- package/chunks/{chunk-5RUCD4ED.js → chunk-WPVUOVYX.js} +3 -3
- package/chunks/{chunk-EJOGLSNJ.js → chunk-WSSH2BNO.js} +2 -2
- package/chunks/{chunk-5AFGJNY6.js → chunk-WVIABDXV.js} +4 -4
- package/chunks/chunk-WZAD4ZNJ.js +59 -0
- package/chunks/{chunk-62X3CM7Q.js → chunk-X3YA3YGG.js} +8 -5
- package/chunks/{chunk-EBPLKY6U.js → chunk-XC377TLN.js} +5483 -3168
- package/chunks/{chunk-KLOMACIR.js → chunk-XLLKYULU.js} +2 -2
- package/chunks/{chunk-QSD4UH74.js → chunk-XO24LIZC.js} +254 -56
- package/chunks/{chunk-N4SVADAV.js → chunk-XT4RKHVE.js} +5 -4
- package/chunks/{chunk-PVXEJB66.js → chunk-XUJNK7Y6.js} +1 -1
- package/chunks/{chunk-YBHUXEC6.js → chunk-YECDICIO.js} +3 -3
- package/chunks/{chunk-FA5K6YI2.js → chunk-YFPZ3NNC.js} +36 -4
- package/chunks/{chunk-46UV252V.js → chunk-YHC2EYYG.js} +35 -38
- package/chunks/{chunk-6SPD4Z7F.js → chunk-YIWH3MKK.js} +8 -3
- package/chunks/{chunk-ZMY2P4L3.js → chunk-YXC7JYUI.js} +4 -4
- package/chunks/{chunk-TB4YFWXG.js → chunk-YZHRN3CF.js} +2 -2
- package/chunks/{chunk-TQDFSQQF.js → chunk-YZOSNW4R.js} +1 -1
- package/chunks/{chunk-DD6O3ZRD.js → chunk-ZIGC3MUS.js} +3 -5
- package/chunks/{chunk-CZ4OWGQQ.js → chunk-ZXEAEZFN.js} +63 -19
- package/chunks/{computer-use-F4URV4TU.js → computer-use-ABECHPS5.js} +42 -41
- package/chunks/{config-utils-Z3OW3IQG.js → config-utils-NJQA5YLJ.js} +2 -2
- package/chunks/{contextCommand-IGSS2U5J.js → contextCommand-4CD5HZQQ.js} +44 -43
- package/chunks/{core-runtime-H5CZDN3A.js → core-runtime-2MOVQ4VX.js} +42 -41
- package/chunks/{create-sub-session-XT6DLYOE.js → create-sub-session-KRQULJE6.js} +2 -2
- package/chunks/{create-sub-session-PA7MFTHK.js → create-sub-session-L6NNHG5N.js} +46 -44
- package/chunks/{cron-create-2JZ2TWTF.js → cron-create-NFRZEOQX.js} +4 -4
- package/chunks/{cron-delete-CTPD2P26.js → cron-delete-GFVSVO7C.js} +4 -4
- package/chunks/{cron-list-V44KHAF6.js → cron-list-NRW34CLU.js} +4 -4
- package/chunks/{daemon-GED37WOX.js → daemon-XH76IXOC.js} +436 -29
- package/chunks/{daemon-git-worktree-guard-LZDCNJGV.js → daemon-git-worktree-guard-BLXFEG4Q.js} +44 -43
- package/chunks/daemon-status-provider-XGD3TPTO.js +103 -0
- package/chunks/daemon-trust-policy-THEGCWPO.js +100 -0
- package/chunks/{daemon-trust-policy-monitor-2K2YETMT.js → daemon-trust-policy-monitor-L7L4ACWQ.js} +49 -48
- package/chunks/{de-UBEBKG6V.js → de-AH4LGCF5.js} +8 -0
- package/chunks/{deferred-core-runtime-FKJ3OYE7.js → deferred-core-runtime-YQLHDUGE.js} +42 -41
- package/chunks/discovery-X2NV535U.js +27 -0
- package/chunks/{display-image-M2ELAVN4.js → display-image-ON3EYFRD.js} +4 -4
- package/chunks/{dist-WJ4BHIEW.js → dist-ESS34DHC.js} +72 -0
- package/chunks/{earlyInputCapture-WJBSJQUF.js → earlyInputCapture-PCTXNW7N.js} +43 -42
- package/chunks/{edit-X73LA4YO.js → edit-QX2EGWYW.js} +45 -43
- package/chunks/{en-X6YV7GME.js → en-MD3GP5YL.js} +8 -0
- package/chunks/{enter-worktree-CLRQTIVN.js → enter-worktree-EM3ZZ2SB.js} +42 -41
- package/chunks/{enterPlanMode-6BDYUQ5T.js → enterPlanMode-ESCMVAKB.js} +42 -41
- package/chunks/{environment-WOAJXJDJ.js → environment-TOJI56YV.js} +45 -44
- package/chunks/{errors-7OY5MXYY.js → errors-DZ5FWWEM.js} +44 -43
- package/chunks/{exit-worktree-TFFJXCRT.js → exit-worktree-KUIJ36XA.js} +42 -41
- package/chunks/exitPlanMode-NFVY54FV.js +86 -0
- package/chunks/{fast-path-QQLGC37M.js → fast-path-JLQXJSH6.js} +3 -3
- package/chunks/{fast-path-settings-LNOFM2YP.js → fast-path-settings-WHX3J3ZI.js} +2 -2
- package/chunks/{fr-VENTC2BS.js → fr-ZEML2JWS.js} +8 -0
- package/chunks/{gemini-VHE62IJL.js → gemini-I7OT4FWL.js} +92 -91
- package/chunks/{geminiContentGenerator-VSHIEGAQ.js → geminiContentGenerator-GRIS77NJ.js} +6 -6
- package/chunks/{glob-VMEEDDLO.js → glob-7TBUUV6R.js} +42 -41
- package/chunks/{goal-tools-M4UDAZXP.js → goal-tools-K5OHOJ6B.js} +56 -12
- package/chunks/{grep-F4UAR7KX.js → grep-743SYWCZ.js} +42 -41
- package/chunks/handleAutoUpdate-GAOYUYOD.js +95 -0
- package/chunks/{i18n-ETW24DHW.js → i18n-2ITURYX6.js} +43 -42
- package/chunks/{image-gen-YPK2AZT4.js → image-gen-4OIWDZD6.js} +10 -10
- package/chunks/initializer-OC7LWA6X.js +101 -0
- package/chunks/{installationInfo-P7OTIR4P.js → installationInfo-CO47QX3Q.js} +43 -42
- package/chunks/{ja-QHT4EQTO.js → ja-UM5B2HMD.js} +8 -0
- package/chunks/{keychain-token-storage-NKKCUHI2.js → keychain-token-storage-3XFJ5ZB2.js} +2 -2
- package/chunks/list-ATR2SFWT.js +104 -0
- package/chunks/{list-agents-O6WSY4CT.js → list-agents-OSVDFI6S.js} +2 -2
- package/chunks/loadedSettingsAdapter-NK4B7AGK.js +98 -0
- package/chunks/{loggingContentGenerator-J2J2AANS.js → loggingContentGenerator-3WXBU5TQ.js} +67 -41
- package/chunks/{loop-wakeup-GVQRMUKS.js → loop-wakeup-HWVUU5CF.js} +5 -5
- package/chunks/{ls-6W2D7TKU.js → ls-D3HUFHDP.js} +4 -4
- package/chunks/{lsp-NJ4KFBI2.js → lsp-3QDDJTCS.js} +2 -2
- package/chunks/{managed-npm-update-WMV5ITKU.js → managed-npm-update-4SSBWI2D.js} +43 -42
- package/chunks/mcp-C62AE2QI.js +98 -0
- package/chunks/{monitor-2MM23VDV.js → monitor-FEYEGASA.js} +42 -41
- package/chunks/nonInteractiveCli-AJEV5ZWO.js +165 -0
- package/chunks/{notebook-edit-QD4TRKLY.js → notebook-edit-SLLTEY4O.js} +46 -44
- package/chunks/{openaiContentGenerator-KLHSPVN2.js → openaiContentGenerator-WLUGIAPX.js} +27 -26
- package/chunks/{pidfile-RQGZBNXT.js → pidfile-TV2VWUMB.js} +43 -42
- package/chunks/{processUtils-HZZDA2VV.js → processUtils-3IN2ZR55.js} +2 -2
- package/chunks/proper-lockfile-3LHWIM44.js +8 -0
- package/chunks/{pt-VL3I5RNY.js → pt-5BMJ3XYH.js} +8 -0
- package/chunks/{qwenContentGenerator-T75M2Z3B.js → qwenContentGenerator-GSGRFPJE.js} +47 -46
- package/chunks/{qwenOAuth2-5QZU444W.js → qwenOAuth2-JLSTIS4Z.js} +9 -9
- package/chunks/{read-file-LOVUSBJC.js → read-file-6PZZRGZZ.js} +15 -13
- package/chunks/{read-mcp-resource-GWCP23WG.js → read-mcp-resource-XD54ZQMC.js} +2 -2
- package/chunks/{record-artifact-IYQDEYMV.js → record-artifact-GLU3UWBV.js} +5 -3
- package/chunks/{resumeHistoryUtils-LVKSSQII.js → resumeHistoryUtils-5GEWKOOO.js} +49 -48
- package/chunks/ripGrep-FX7GBGFN.js +86 -0
- package/chunks/{ru-4RCKL4PY.js → ru-6GL66ORV.js} +8 -0
- package/chunks/{run-qwen-serve-GZW7B4WK.js → run-qwen-serve-7RHU3NSV.js} +423 -212
- package/chunks/{runtime-MYRXEO2E.js → runtime-EPOXAMLP.js} +52 -51
- package/chunks/{scheduler-DPTPI6FW.js → scheduler-F4Y7ENVV.js} +44 -43
- package/chunks/{sdk-exporters-http-NHBYB5FZ.js → sdk-exporters-http-NC746HLT.js} +3 -3
- package/chunks/{sdk-impl-SK4P5WON.js → sdk-impl-YVL7BP6Y.js} +3 -3
- package/chunks/{send-message-O7FO63UK.js → send-message-TNBG5EVA.js} +7 -7
- package/chunks/{serve-XCG4XCDA.js → serve-LQV4TN5A.js} +49 -50
- package/chunks/{server-AWQHKXLG.js → server-IZCKLIYQ.js} +5042 -1725
- package/chunks/{session-P5FKNCNR.js → session-52ZGTDVB.js} +87 -85
- package/chunks/{settings-CSYVIP2R.js → settings-WCVB34HW.js} +48 -47
- package/chunks/{shell-EGTSUO2P.js → shell-33BIUBLH.js} +42 -41
- package/chunks/{skill-IFUD72GF.js → skill-IYVQ2QNK.js} +20 -18
- package/chunks/{skill-settings-YOE7LBHE.js → skill-settings-YG4ZS4OZ.js} +48 -47
- package/chunks/{spawnChannel-PQSZIOLY.js → spawnChannel-BLA4YT4W.js} +44 -43
- package/chunks/{standalone-update-RB2EGUSF.js → standalone-update-ALRIPWSM.js} +44 -43
- package/chunks/{startInteractiveUI-KMYUJ2MU.js → startInteractiveUI-PISBXWKA.js} +614 -294
- package/chunks/{syntheticOutput-DVHJMUGV.js → syntheticOutput-7GWFIDXT.js} +3 -3
- package/chunks/{task-create-4NC7PDI4.js → task-create-EILHJJB7.js} +11 -11
- package/chunks/{task-list-LBSRMOC7.js → task-list-WGJR6YL5.js} +21 -7
- package/chunks/{task-stop-YFNATTIM.js → task-stop-X37KYTKB.js} +2 -2
- package/chunks/{task-update-BPLM52GD.js → task-update-XZAHVXJ5.js} +86 -15
- package/chunks/{team-create-B6A6MJBT.js → team-create-CIQDCC6A.js} +43 -43
- package/chunks/{team-delete-MKYMYBFM.js → team-delete-UEP4QOOT.js} +6 -6
- package/chunks/{team-plan-approval-5WO3CXXU.js → team-plan-approval-664XCRB4.js} +42 -41
- package/chunks/{terminal-image-renderer-BTRE2GEU.js → terminal-image-renderer-TEBO6ONY.js} +44 -43
- package/chunks/theme-manager-3CIFH2JV.js +90 -0
- package/chunks/{todoWrite-K5K7NRE5.js → todoWrite-ATS62CAP.js} +4 -4
- package/chunks/{tool-search-QNBLXUGR.js → tool-search-IJX5JHJB.js} +19 -17
- package/chunks/{total-session-admission-N4E5SFBO.js → total-session-admission-XBK2NVRV.js} +46 -45
- package/chunks/{trustedFolders-MQS46LIU.js → trustedFolders-OOFNLRWK.js} +43 -42
- package/chunks/{update-relaunch-536KRL33.js → update-relaunch-EIG7EYAQ.js} +5 -5
- package/chunks/{updateCheck-QJI2SYWF.js → updateCheck-KYDCBLSF.js} +46 -45
- package/chunks/{useAutoAcceptIndicator-7QASHD46.js → useAutoAcceptIndicator-RFX3KNBN.js} +52 -51
- package/chunks/{validateNonInterActiveAuth-ZNRGWBLV.js → validateNonInterActiveAuth-MZXSAITU.js} +83 -81
- package/chunks/{version-DBEQAFRW.js → version-PJC6ZNXV.js} +1 -1
- package/chunks/{web-fetch-MBIVXKPE.js → web-fetch-XXICVGKQ.js} +21 -18
- package/chunks/{web-search-4LBIN6VF.js → web-search-LHPM6QWC.js} +9 -9
- package/chunks/{workflow-LNMA55HY.js → workflow-4CUO2BV7.js} +159 -57
- package/chunks/workspace-providers-status-G4MUGH3X.js +101 -0
- package/chunks/{workspace-registration-store-BGRKKIYR.js → workspace-registration-store-QMDMFWBE.js} +2 -2
- package/chunks/{workspace-registry-L4NCJ34K.js → workspace-registry-FKBB4MZK.js} +48 -46
- package/chunks/{workspace-service-LOXYKYTR.js → workspace-service-TIDTTA65.js} +55 -54
- package/chunks/workspace-skills-status-LBC2TZKM.js +101 -0
- package/chunks/{workspace-trust-reconciler-H36TCR2S.js → workspace-trust-reconciler-4KJ567XP.js} +58 -56
- package/chunks/{write-file-JJAY7JSP.js → write-file-R6LAEER5.js} +42 -41
- package/chunks/{zh-TW-SQ4HTSCW.js → zh-TW-LVLBK4KF.js} +8 -0
- package/chunks/{zh-LMSTK4WD.js → zh-UBMWS2BJ.js} +8 -0
- package/chunks/{zoom-image-4MVVVM7E.js → zoom-image-XLCK6DDK.js} +20 -17
- package/cli.js +13 -13
- package/locales/ca.js +13 -0
- package/locales/de.js +12 -0
- package/locales/en.js +11 -0
- package/locales/fr.js +13 -0
- package/locales/ja.js +13 -0
- package/locales/pt.js +12 -0
- package/locales/ru.js +12 -0
- package/locales/zh-TW.js +11 -0
- package/locales/zh.js +11 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-B-89zHN4.js → arc-DItbX0DI.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-BkcOncHk.js → architectureDiagram-3BPJPVTR-CmnIlH8y.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-DQ4yboaF.js → blockDiagram-GPEHLZMM-pObnB9kw.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-C_8ZjPDI.js → c4Diagram-AAUBKEIU-BNBmMS0Y.js} +1 -1
- package/web-shell/assets/channel-hZnMfWA9.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-naKVe1Bm.js → chunk-2J33WTMH-Dz4JBOO6.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-DdoViKT2.js → chunk-4BX2VUAB-Cz2GnvAR.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DUDQZEwU.js → chunk-55IACEB6-CC6kOQYx.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-BqpDTR5s.js → chunk-727SXJPM-Z4lY4gbh.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-CdmEknkT.js → chunk-AQP2D5EJ-Yz0hZr3D.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-CH7fFTLB.js → chunk-FMBD7UC4-nKmTWTv9.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-ObgSuFKF.js → chunk-ND2GUHAM-CjZz0f6Y.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-D9fKdv_s.js → chunk-QZHKN3VN-Bab3FpuS.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BRnxm8DX.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BRnxm8DX.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-CvzATMx9.js → cose-bilkent-S5V4N54A-BuSAGFox.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-M_xU21QW.js → dagre-BM42HDAG-CRZXTg3g.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CNrl9sW1.js → diagram-2AECGRRQ-BFx1Ayrz.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-CUweVT6T.js → diagram-5GNKFQAL-B2hMZ3gS.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-D3n6Lxjo.js → diagram-KO2AKTUF-DKxAQLmc.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-0SeFPK4t.js → diagram-LMA3HP47-Bo1xGqVY.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-DAgyEwge.js → diagram-OG6HWLK6-B9NG78d-.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-CzxBBDIK.js → erDiagram-TEJ5UH35-DltQKiqQ.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-B0uj0jyo.js → flowDiagram-I6XJVG4X-5xXGmS4I.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-DFzcj5km.js → ganttDiagram-6RSMTGT7-bhGL5n0l.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-DylJ_Fc9.js → gitGraphDiagram-PVQCEYII-ZYnz9hgh.js} +1 -1
- package/web-shell/assets/{index-BKSAnXU9.js → index-CBBeUArD.js} +1 -1
- package/web-shell/assets/index-CbgU-jUo.css +5 -0
- package/web-shell/assets/index-_nhzXqab.js +1750 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-BYMcJVMI.js → infoDiagram-5YYISTIA-Cg-jamQf.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-t1quI1S3.js → ishikawaDiagram-YF4QCWOH-CcmvKlyq.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-YM_QVUJm.js → journeyDiagram-JHISSGLW-BRsOQZp1.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-jw8OddK1.js → kanban-definition-UN3LZRKU-xW-dmEHK.js} +1 -1
- package/web-shell/assets/{linear-Dlr3RVuP.js → linear-ClBfEZH2.js} +1 -1
- package/web-shell/assets/{mermaid.core-CqGKzNzd.js → mermaid.core-D65NDkzc.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BqureoOS.js → mindmap-definition-RKZ34NQL-CyvFslYa.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-Da20HkK1.js → pieDiagram-4H26LBE5-BwSefMyG.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BsNlMvJy.js → quadrantDiagram-W4KKPZXB-GqBJspFS.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-DzVCQCse.js → requirementDiagram-4Y6WPE33-B137PlTJ.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-BMo16voT.js → sankeyDiagram-5OEKKPKP-maHkkt8i.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-Bgi-pdHk.js → sequenceDiagram-3UESZ5HK-DJ1mRaG3.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-xaPQXwGk.js → stateDiagram-AJRCARHV-aRmP7Q4i.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Db39gvZ_.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-C_9RuvKG.js → timeline-definition-PNZ67QCA-CIQ3BRPA.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-Bgu6vdla.js → vennDiagram-CIIHVFJN-DR9VPd5h.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-CFTZ8IrX.js → wardley-L42UT6IY-ZcfIbT4D.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-BASW9Vmt.js → wardleyDiagram-YWT4CUSO-D0jgPi4T.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6--Nh-CD3F.js → xychartDiagram-2RQKCTM6-BGWU4s5o.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/agent-headless-OEQNFOMH.js +0 -87
- package/chunks/chunk-DEDESZDL.js +0 -358
- package/chunks/chunk-MPHPFVKK.js +0 -48
- package/chunks/chunk-UI5UGEF4.js +0 -3576
- package/chunks/daemon-status-provider-QYM57Z44.js +0 -102
- package/chunks/daemon-trust-policy-TSRVEYZR.js +0 -99
- package/chunks/discovery-XLHITE74.js +0 -220
- package/chunks/exitPlanMode-WDURQMIU.js +0 -85
- package/chunks/handleAutoUpdate-GN7Z6QAC.js +0 -94
- package/chunks/initializer-UA6KQ7MS.js +0 -100
- package/chunks/list-GRAMIQOT.js +0 -103
- package/chunks/loadedSettingsAdapter-5O2TDS3I.js +0 -97
- package/chunks/mcp-XLP33CAI.js +0 -97
- package/chunks/nonInteractiveCli-KTA5K6FS.js +0 -163
- package/chunks/ripGrep-ZJSHKB6H.js +0 -85
- package/chunks/theme-manager-XL2N5SBY.js +0 -89
- package/chunks/workspace-providers-status-PDDMI6ST.js +0 -100
- package/chunks/workspace-skills-status-IJ5FOQI6.js +0 -100
- package/web-shell/assets/channel-Du2WFns8.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-Zw0HafH6.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Zw0HafH6.js +0 -1
- package/web-shell/assets/index-BIGQygTL.css +0 -5
- package/web-shell/assets/index-J7OMTqAN.js +0 -1789
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-D5RqimXD.js +0 -1
- package/chunks/{chunk-SYHXR6WM.js → chunk-4W5U2TUT.js} +3 -3
- /package/chunks/{chunk-NTTBXH7U.js → chunk-UGK4K2N2.js} +0 -0
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "./chunk-OCPBI7J5.js";
|
|
20
20
|
import {
|
|
21
21
|
defaultSpawnChannelFactory
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-BQWNIPTE.js";
|
|
23
23
|
import {
|
|
24
24
|
BridgeChannelClosedError,
|
|
25
25
|
BridgeTimeoutError,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
SessionRestoreTimeoutError,
|
|
30
30
|
createIdleWorkspaceExtensionsStatus,
|
|
31
31
|
createIdleWorkspaceHooksStatus
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-UC67T4SF.js";
|
|
33
33
|
import {
|
|
34
34
|
ACTIVE_WORK_CLOSE_IF_UNHELD_PARAM,
|
|
35
35
|
ACTIVE_WORK_CLOSE_TIMEOUT_MS,
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
CHANNEL_STARTUP_PROFILE_META_KEY,
|
|
46
46
|
CHANNEL_STARTUP_PROFILE_VERSION,
|
|
47
47
|
DAEMON_CHANNEL_DELIVERY_META_KEY,
|
|
48
|
+
DAEMON_MEDIA_REFERENCES_META_KEY,
|
|
48
49
|
DAEMON_MODEL_PROMPT_META_KEY,
|
|
49
50
|
DAEMON_PROMPT_DISPLAY_TEXT_META_KEY,
|
|
50
51
|
LOAD_REPLAY_BULK_MODE,
|
|
@@ -62,8 +63,9 @@ import {
|
|
|
62
63
|
TODO_STOP_GUARD_QUEUE_RELEASE_METHOD,
|
|
63
64
|
WORKTREE_MCP_DEFER_META_KEY,
|
|
64
65
|
clampActiveWorkIntervalMs,
|
|
65
|
-
isValidTrustedModelPrompt
|
|
66
|
-
|
|
66
|
+
isValidTrustedModelPrompt,
|
|
67
|
+
sessionCloseDrainBudgetMs
|
|
68
|
+
} from "./chunk-WP4WIUOJ.js";
|
|
67
69
|
import {
|
|
68
70
|
BranchWhilePromptActiveError,
|
|
69
71
|
BridgeChannelQuarantinedError,
|
|
@@ -112,6 +114,8 @@ import {
|
|
|
112
114
|
SESSION_ARTIFACT_PERSISTENCE_VERSION,
|
|
113
115
|
SESSION_TRANSCRIPT_MAX_LIMIT,
|
|
114
116
|
ShellExecutionService,
|
|
117
|
+
TURN_RESULT_CODE_TEXT_TRUNCATED,
|
|
118
|
+
TURN_RESULT_TEXT_MAX_CHARS,
|
|
115
119
|
TrustGateError,
|
|
116
120
|
WORKSPACE_CONTENT_MTIME_MS_METADATA_KEY,
|
|
117
121
|
WORKSPACE_CONTENT_SHA256_METADATA_KEY,
|
|
@@ -119,17 +123,18 @@ import {
|
|
|
119
123
|
isReservedWorkspaceMetadataKey,
|
|
120
124
|
metadataBudgetBytes,
|
|
121
125
|
normalizeSnapshotPayload,
|
|
126
|
+
normalizeTurnResultError,
|
|
122
127
|
stableSessionArtifactId
|
|
123
|
-
} from "./chunk-
|
|
128
|
+
} from "./chunk-XC377TLN.js";
|
|
124
129
|
import {
|
|
125
130
|
DAEMON_TRACEPARENT_META_KEY,
|
|
126
131
|
DAEMON_TRACESTATE_META_KEY
|
|
127
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-OO4FKHLO.js";
|
|
128
133
|
import {
|
|
129
134
|
INVOCATION_CONTEXT_META_KEY,
|
|
130
135
|
PRIVATE_ACP_CAPABILITY_ENV,
|
|
131
136
|
PRIVATE_PARENT_CAPABILITY_META_KEY
|
|
132
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-KC4WMLZO.js";
|
|
133
138
|
import {
|
|
134
139
|
init_esbuild_shims
|
|
135
140
|
} from "./chunk-5O2XNYP6.js";
|
|
@@ -139,8 +144,8 @@ import {
|
|
|
139
144
|
|
|
140
145
|
// packages/acp-bridge/src/bridge.ts
|
|
141
146
|
init_esbuild_shims();
|
|
142
|
-
import { randomBytes, randomUUID as
|
|
143
|
-
import * as
|
|
147
|
+
import { randomBytes, randomUUID as randomUUID3 } from "node:crypto";
|
|
148
|
+
import * as path4 from "node:path";
|
|
144
149
|
import { inspect } from "node:util";
|
|
145
150
|
|
|
146
151
|
// packages/acp-bridge/src/compactionEngine.ts
|
|
@@ -604,7 +609,7 @@ var TurnBoundaryCompactionEngine = class {
|
|
|
604
609
|
const slot = this.slots[existingIdx];
|
|
605
610
|
slot.chunks.push(text);
|
|
606
611
|
if (event.id !== void 0) slot.lastEventId = event.id;
|
|
607
|
-
slot.lastMeta =
|
|
612
|
+
slot.lastMeta = mergeTranscriptUpdateMeta(slot.lastMeta, meta);
|
|
608
613
|
slot.lastEnvelopeMeta = event._meta ?? slot.lastEnvelopeMeta;
|
|
609
614
|
slot.lastTurn = captureTurnFields(event, slot.lastTurn);
|
|
610
615
|
slot.lastSessionId = captureSessionId(event) ?? slot.lastSessionId;
|
|
@@ -628,7 +633,7 @@ var TurnBoundaryCompactionEngine = class {
|
|
|
628
633
|
if (lastSlot && lastSlot.kind === kind && lastSlot.parentToolCallId == null && stringArraysEqual(lastSlot.sourceRecordIds, sourceRecordIds)) {
|
|
629
634
|
lastSlot.chunks.push(text);
|
|
630
635
|
if (event.id !== void 0) lastSlot.lastEventId = event.id;
|
|
631
|
-
lastSlot.lastMeta =
|
|
636
|
+
lastSlot.lastMeta = mergeTranscriptUpdateMeta(lastSlot.lastMeta, meta);
|
|
632
637
|
lastSlot.lastEnvelopeMeta = event._meta ?? lastSlot.lastEnvelopeMeta;
|
|
633
638
|
lastSlot.lastTurn = captureTurnFields(event, lastSlot.lastTurn);
|
|
634
639
|
lastSlot.lastSessionId = captureSessionId(event) ?? lastSlot.lastSessionId;
|
|
@@ -1053,13 +1058,26 @@ function mergeTranscriptUpdateMeta(existing, incoming) {
|
|
|
1053
1058
|
...extractSourceRecordIdsFromMeta(incomingRecord) ?? []
|
|
1054
1059
|
])
|
|
1055
1060
|
];
|
|
1061
|
+
const existingTranscript = extractTranscriptMeta(existingRecord);
|
|
1062
|
+
const incomingTranscript = extractTranscriptMeta(incomingRecord);
|
|
1056
1063
|
return {
|
|
1057
1064
|
...existingRecord ?? {},
|
|
1058
1065
|
...incomingRecord ?? {},
|
|
1059
|
-
...sourceRecordIds.length > 0 ? {
|
|
1066
|
+
...existingTranscript || incomingTranscript || sourceRecordIds.length > 0 ? {
|
|
1067
|
+
qwenTranscript: {
|
|
1068
|
+
...existingTranscript ?? {},
|
|
1069
|
+
...incomingTranscript ?? {},
|
|
1070
|
+
...sourceRecordIds.length > 0 ? { sourceRecordIds } : {}
|
|
1071
|
+
}
|
|
1072
|
+
} : {}
|
|
1060
1073
|
};
|
|
1061
1074
|
}
|
|
1062
1075
|
__name(mergeTranscriptUpdateMeta, "mergeTranscriptUpdateMeta");
|
|
1076
|
+
function extractTranscriptMeta(meta) {
|
|
1077
|
+
const transcript = meta?.["qwenTranscript"];
|
|
1078
|
+
return typeof transcript === "object" && transcript !== null ? transcript : void 0;
|
|
1079
|
+
}
|
|
1080
|
+
__name(extractTranscriptMeta, "extractTranscriptMeta");
|
|
1063
1081
|
|
|
1064
1082
|
// packages/acp-bridge/src/journalGrowthPolicy.ts
|
|
1065
1083
|
init_esbuild_shims();
|
|
@@ -1266,6 +1284,267 @@ function getChannelStartupProfileAttributes(response, receivedAtEpochMs, initial
|
|
|
1266
1284
|
}
|
|
1267
1285
|
__name(getChannelStartupProfileAttributes, "getChannelStartupProfileAttributes");
|
|
1268
1286
|
|
|
1287
|
+
// packages/acp-bridge/src/sessionMedia.ts
|
|
1288
|
+
init_esbuild_shims();
|
|
1289
|
+
import { randomUUID } from "node:crypto";
|
|
1290
|
+
import { promises as fs } from "node:fs";
|
|
1291
|
+
import { tmpdir } from "node:os";
|
|
1292
|
+
import * as path from "node:path";
|
|
1293
|
+
var SESSION_MEDIA_MAX_ITEM_BYTES = 8 * 1024 * 1024;
|
|
1294
|
+
var SESSION_MEDIA_MAX_TOTAL_BYTES = 100 * 1024 * 1024;
|
|
1295
|
+
var SESSION_MEDIA_MAX_ITEMS = 256;
|
|
1296
|
+
var SESSION_MEDIA_UNAVAILABLE_TEXT = "[Attached media is no longer available]";
|
|
1297
|
+
var SessionMediaReferenceError = class extends Error {
|
|
1298
|
+
constructor(message, code) {
|
|
1299
|
+
super(message);
|
|
1300
|
+
this.code = code;
|
|
1301
|
+
this.name = "SessionMediaReferenceError";
|
|
1302
|
+
}
|
|
1303
|
+
static {
|
|
1304
|
+
__name(this, "SessionMediaReferenceError");
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
function isSessionMediaReference(value) {
|
|
1308
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1309
|
+
const record = value;
|
|
1310
|
+
return record["type"] === "image" && typeof record["mediaId"] === "string" && record["mediaId"].length > 0 && typeof record["mimeType"] === "string" && record["mimeType"].startsWith(`${record["type"]}/`) && typeof record["size"] === "number" && Number.isSafeInteger(record["size"]) && record["size"] > 0;
|
|
1311
|
+
}
|
|
1312
|
+
__name(isSessionMediaReference, "isSessionMediaReference");
|
|
1313
|
+
function withMediaDegradationMarker(blocks) {
|
|
1314
|
+
for (let i = blocks.length - 1; i >= 0; i--) {
|
|
1315
|
+
const block = blocks[i];
|
|
1316
|
+
if (block.type === "text") {
|
|
1317
|
+
if (block.text.endsWith(SESSION_MEDIA_UNAVAILABLE_TEXT)) {
|
|
1318
|
+
return [...blocks];
|
|
1319
|
+
}
|
|
1320
|
+
const next = [...blocks];
|
|
1321
|
+
next[i] = {
|
|
1322
|
+
type: "text",
|
|
1323
|
+
text: `${block.text}
|
|
1324
|
+
${SESSION_MEDIA_UNAVAILABLE_TEXT}`
|
|
1325
|
+
};
|
|
1326
|
+
return next;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return [
|
|
1330
|
+
...blocks,
|
|
1331
|
+
{ type: "text", text: SESSION_MEDIA_UNAVAILABLE_TEXT }
|
|
1332
|
+
];
|
|
1333
|
+
}
|
|
1334
|
+
__name(withMediaDegradationMarker, "withMediaDegradationMarker");
|
|
1335
|
+
var SessionMediaStore = class {
|
|
1336
|
+
static {
|
|
1337
|
+
__name(this, "SessionMediaStore");
|
|
1338
|
+
}
|
|
1339
|
+
records = /* @__PURE__ */ new Map();
|
|
1340
|
+
directoryPromise;
|
|
1341
|
+
totalBytes = 0;
|
|
1342
|
+
pendingItems = 0;
|
|
1343
|
+
closed = false;
|
|
1344
|
+
async put(data, mimeType) {
|
|
1345
|
+
if (this.closed) throw new Error("Session media store is closed");
|
|
1346
|
+
const type = "image";
|
|
1347
|
+
if (!mimeType.startsWith("image/")) {
|
|
1348
|
+
throw new TypeError("Session media must be image/*");
|
|
1349
|
+
}
|
|
1350
|
+
if (data.byteLength === 0 || data.byteLength > SESSION_MEDIA_MAX_ITEM_BYTES) {
|
|
1351
|
+
throw new RangeError(
|
|
1352
|
+
`Session media must be between 1 and ${SESSION_MEDIA_MAX_ITEM_BYTES} bytes`
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
1355
|
+
if (this.totalBytes + data.byteLength > SESSION_MEDIA_MAX_TOTAL_BYTES) {
|
|
1356
|
+
throw new RangeError(
|
|
1357
|
+
`Session media exceeds the ${SESSION_MEDIA_MAX_TOTAL_BYTES}-byte session limit`
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
if (this.records.size + this.pendingItems >= SESSION_MEDIA_MAX_ITEMS) {
|
|
1361
|
+
throw new RangeError(
|
|
1362
|
+
`Session media exceeds the ${SESSION_MEDIA_MAX_ITEMS}-item session limit`
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
const mediaId = randomUUID();
|
|
1366
|
+
let filePath;
|
|
1367
|
+
this.totalBytes += data.byteLength;
|
|
1368
|
+
this.pendingItems += 1;
|
|
1369
|
+
try {
|
|
1370
|
+
const directory = await this.directory();
|
|
1371
|
+
filePath = path.join(directory, mediaId);
|
|
1372
|
+
await fs.writeFile(filePath, data, { flag: "wx" });
|
|
1373
|
+
if (this.closed) {
|
|
1374
|
+
throw new Error("Session media store is closed");
|
|
1375
|
+
}
|
|
1376
|
+
const record = {
|
|
1377
|
+
type,
|
|
1378
|
+
mediaId,
|
|
1379
|
+
mimeType,
|
|
1380
|
+
size: data.byteLength,
|
|
1381
|
+
filePath
|
|
1382
|
+
};
|
|
1383
|
+
this.records.set(mediaId, record);
|
|
1384
|
+
return { type, mediaId, mimeType, size: data.byteLength };
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
if (filePath) await fs.rm(filePath, { force: true }).catch(() => {
|
|
1387
|
+
});
|
|
1388
|
+
if (!this.closed) this.totalBytes -= data.byteLength;
|
|
1389
|
+
throw error;
|
|
1390
|
+
} finally {
|
|
1391
|
+
if (!this.closed) this.pendingItems -= 1;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
// Validate one block against the store. Blocks without a `mediaId` (inline
|
|
1395
|
+
// media, text) pass through untouched, matching `assertReferences`.
|
|
1396
|
+
assertReference(block) {
|
|
1397
|
+
if (!block || typeof block !== "object" || Array.isArray(block) || !("mediaId" in block)) {
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
if (!isSessionMediaReference(block)) {
|
|
1401
|
+
throw new SessionMediaReferenceError(
|
|
1402
|
+
"Invalid session media reference",
|
|
1403
|
+
"invalid_session_media_reference"
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
this.assertStored(block);
|
|
1407
|
+
}
|
|
1408
|
+
assertReferences(content) {
|
|
1409
|
+
const seenMediaIds = /* @__PURE__ */ new Set();
|
|
1410
|
+
for (const block of content) {
|
|
1411
|
+
if (!block || typeof block !== "object" || Array.isArray(block) || !("mediaId" in block)) {
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
if (!isSessionMediaReference(block)) {
|
|
1415
|
+
throw new SessionMediaReferenceError(
|
|
1416
|
+
"Invalid session media reference",
|
|
1417
|
+
"invalid_session_media_reference"
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
if (seenMediaIds.has(block.mediaId)) {
|
|
1421
|
+
throw new SessionMediaReferenceError(
|
|
1422
|
+
`Session media referenced more than once: ${block.mediaId}`,
|
|
1423
|
+
"invalid_session_media_reference"
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
seenMediaIds.add(block.mediaId);
|
|
1427
|
+
this.assertStored(block);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
async resolveContent(content, memo) {
|
|
1431
|
+
const pendingByMediaId = memo ?? /* @__PURE__ */ new Map();
|
|
1432
|
+
return await Promise.all(
|
|
1433
|
+
content.map(async (block) => {
|
|
1434
|
+
if (!isSessionMediaReference(block)) return block;
|
|
1435
|
+
let pending = pendingByMediaId.get(block.mediaId);
|
|
1436
|
+
if (!pending) {
|
|
1437
|
+
const created = this.resolve(block);
|
|
1438
|
+
pendingByMediaId.set(block.mediaId, created);
|
|
1439
|
+
void created.catch(() => {
|
|
1440
|
+
if (pendingByMediaId.get(block.mediaId) === created) {
|
|
1441
|
+
pendingByMediaId.delete(block.mediaId);
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
pending = created;
|
|
1445
|
+
}
|
|
1446
|
+
return await pending;
|
|
1447
|
+
})
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
// Per-block variant of `resolveContent` for degrade paths: one unresolvable
|
|
1451
|
+
// reference drops only itself, keeping the sibling blocks a wholesale
|
|
1452
|
+
// fallback would discard. Non-media errors still propagate.
|
|
1453
|
+
async resolveContentDegrading(content, memo) {
|
|
1454
|
+
const retainedBlocks = [];
|
|
1455
|
+
const resolvedBlocks = [];
|
|
1456
|
+
let degraded = 0;
|
|
1457
|
+
for (const block of content) {
|
|
1458
|
+
if (!isSessionMediaReference(block)) {
|
|
1459
|
+
retainedBlocks.push(block);
|
|
1460
|
+
resolvedBlocks.push(block);
|
|
1461
|
+
continue;
|
|
1462
|
+
}
|
|
1463
|
+
try {
|
|
1464
|
+
const [resolved] = await this.resolveContent([block], memo);
|
|
1465
|
+
if (resolved) resolvedBlocks.push(resolved);
|
|
1466
|
+
retainedBlocks.push(block);
|
|
1467
|
+
} catch (error) {
|
|
1468
|
+
if (!(error instanceof SessionMediaReferenceError)) throw error;
|
|
1469
|
+
degraded += 1;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return { retainedBlocks, resolvedBlocks, degraded };
|
|
1473
|
+
}
|
|
1474
|
+
async read(mediaId) {
|
|
1475
|
+
const record = this.records.get(mediaId);
|
|
1476
|
+
if (!record) return void 0;
|
|
1477
|
+
try {
|
|
1478
|
+
return {
|
|
1479
|
+
data: await fs.readFile(record.filePath),
|
|
1480
|
+
mimeType: record.mimeType
|
|
1481
|
+
};
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
if (error.code === "ENOENT") {
|
|
1484
|
+
if (this.records.delete(mediaId)) this.totalBytes -= record.size;
|
|
1485
|
+
return void 0;
|
|
1486
|
+
}
|
|
1487
|
+
throw error;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
async remove(mediaId) {
|
|
1491
|
+
const record = this.records.get(mediaId);
|
|
1492
|
+
if (!record) return false;
|
|
1493
|
+
this.records.delete(mediaId);
|
|
1494
|
+
this.totalBytes -= record.size;
|
|
1495
|
+
await fs.rm(record.filePath, { force: true });
|
|
1496
|
+
return true;
|
|
1497
|
+
}
|
|
1498
|
+
get sizeBytes() {
|
|
1499
|
+
return this.totalBytes;
|
|
1500
|
+
}
|
|
1501
|
+
async close() {
|
|
1502
|
+
if (this.closed) return;
|
|
1503
|
+
this.closed = true;
|
|
1504
|
+
this.records.clear();
|
|
1505
|
+
this.totalBytes = 0;
|
|
1506
|
+
this.pendingItems = 0;
|
|
1507
|
+
if (!this.directoryPromise) return;
|
|
1508
|
+
const directory = await this.directoryPromise.catch(() => void 0);
|
|
1509
|
+
if (!directory) return;
|
|
1510
|
+
await fs.rm(directory, { recursive: true, force: true });
|
|
1511
|
+
}
|
|
1512
|
+
assertStored(reference) {
|
|
1513
|
+
const stored = this.records.get(reference.mediaId);
|
|
1514
|
+
if (!stored || stored.type !== reference.type || stored.mimeType !== reference.mimeType || stored.size !== reference.size) {
|
|
1515
|
+
throw new SessionMediaReferenceError(
|
|
1516
|
+
`Unknown or unavailable session media: ${reference.mediaId}`,
|
|
1517
|
+
"session_media_gone"
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
async resolve(reference) {
|
|
1522
|
+
const media = await this.read(reference.mediaId);
|
|
1523
|
+
if (!media || media.mimeType !== reference.mimeType) {
|
|
1524
|
+
throw new SessionMediaReferenceError(
|
|
1525
|
+
`Unknown or unavailable session media: ${reference.mediaId}`,
|
|
1526
|
+
"session_media_gone"
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
return {
|
|
1530
|
+
type: reference.type,
|
|
1531
|
+
data: media.data.toString("base64"),
|
|
1532
|
+
mimeType: media.mimeType
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
async directory() {
|
|
1536
|
+
if (!this.directoryPromise) {
|
|
1537
|
+
const pending = fs.mkdtemp(path.join(tmpdir(), "qwen-session-media-"));
|
|
1538
|
+
this.directoryPromise = pending;
|
|
1539
|
+
void pending.catch(() => {
|
|
1540
|
+
if (this.directoryPromise === pending)
|
|
1541
|
+
this.directoryPromise = void 0;
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
return await this.directoryPromise;
|
|
1545
|
+
}
|
|
1546
|
+
};
|
|
1547
|
+
|
|
1269
1548
|
// packages/acp-bridge/src/internal/stderrLine.ts
|
|
1270
1549
|
init_esbuild_shims();
|
|
1271
1550
|
function writeStderrLine(message) {
|
|
@@ -1276,9 +1555,9 @@ __name(writeStderrLine, "writeStderrLine");
|
|
|
1276
1555
|
|
|
1277
1556
|
// packages/acp-bridge/src/bridgeClient.ts
|
|
1278
1557
|
init_esbuild_shims();
|
|
1279
|
-
import { randomUUID } from "node:crypto";
|
|
1280
|
-
import { promises as
|
|
1281
|
-
import * as
|
|
1558
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1559
|
+
import { promises as fs2 } from "node:fs";
|
|
1560
|
+
import * as path2 from "node:path";
|
|
1282
1561
|
|
|
1283
1562
|
// packages/acp-bridge/src/daemonEventTypes.ts
|
|
1284
1563
|
init_esbuild_shims();
|
|
@@ -2264,7 +2543,7 @@ function sliceLineRange(content, startLine, endLine) {
|
|
|
2264
2543
|
}
|
|
2265
2544
|
__name(sliceLineRange, "sliceLineRange");
|
|
2266
2545
|
var BridgeClient = class {
|
|
2267
|
-
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender, ownsSession = () => true, onTokenUsage, onCreateSubSession, onGenerationEvent, onWorkspaceGenerationEvent, onChannelDelivery, hasSessionSpawnInFlight = () => false, getLiveScreenContextCaptureHandler = () => void 0, getLiveTaskToolRequestHandler = () => void 0, getLiveSpeakToUserHandler = () => void 0, externalToolGuard, onActiveWork) {
|
|
2546
|
+
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender, ownsSession = () => true, onTokenUsage, onCreateSubSession, onGenerationEvent, onWorkspaceGenerationEvent, onChannelDelivery, hasSessionSpawnInFlight = () => false, getLiveScreenContextCaptureHandler = () => void 0, getLiveTaskToolRequestHandler = () => void 0, getLiveSpeakToUserHandler = () => void 0, externalToolGuard, onActiveWork, onSessionCatalogChanged) {
|
|
2268
2547
|
this.resolveEntry = resolveEntry;
|
|
2269
2548
|
this.resolvePendingRestoreEvents = resolvePendingRestoreEvents;
|
|
2270
2549
|
this.mediator = mediator;
|
|
@@ -2286,6 +2565,7 @@ var BridgeClient = class {
|
|
|
2286
2565
|
this.getLiveSpeakToUserHandler = getLiveSpeakToUserHandler;
|
|
2287
2566
|
this.externalToolGuard = externalToolGuard;
|
|
2288
2567
|
this.onActiveWork = onActiveWork;
|
|
2568
|
+
this.onSessionCatalogChanged = onSessionCatalogChanged;
|
|
2289
2569
|
}
|
|
2290
2570
|
static {
|
|
2291
2571
|
__name(this, "BridgeClient");
|
|
@@ -2304,7 +2584,7 @@ var BridgeClient = class {
|
|
|
2304
2584
|
options.map((o) => String(o.optionId ?? ""))
|
|
2305
2585
|
);
|
|
2306
2586
|
allowedOptionIds.delete("");
|
|
2307
|
-
const requestId =
|
|
2587
|
+
const requestId = randomUUID2();
|
|
2308
2588
|
if (allowedOptionIds.has(CANCEL_VOTE_SENTINEL)) {
|
|
2309
2589
|
throw new CancelSentinelCollisionError(requestId, CANCEL_VOTE_SENTINEL);
|
|
2310
2590
|
}
|
|
@@ -2550,8 +2830,8 @@ var BridgeClient = class {
|
|
|
2550
2830
|
* between tool batches to pull any messages the browser queued mid-turn. We splice the per-session
|
|
2551
2831
|
* queue, return them to the child as the response, and — when non-empty —
|
|
2552
2832
|
* publish a `mid_turn_message_injected` SSE frame so the browser can move
|
|
2553
|
-
* those messages out of its pending queue
|
|
2554
|
-
*
|
|
2833
|
+
* those messages out of its pending queue and render the immediate echo.
|
|
2834
|
+
* Unknown methods reject with ACP `methodNotFound` (-32601), matching
|
|
2555
2835
|
* the SDK's
|
|
2556
2836
|
* default for an unimplemented client surface; the child's drain caller
|
|
2557
2837
|
* treats that as "drain unsupported" and stops asking.
|
|
@@ -2585,9 +2865,12 @@ var BridgeClient = class {
|
|
|
2585
2865
|
throw RequestError.methodNotFound(method);
|
|
2586
2866
|
}
|
|
2587
2867
|
const sessionId = typeof params["sessionId"] === "string" ? params["sessionId"] : void 0;
|
|
2588
|
-
if (!sessionId) return { messages: [], hasQueuedPrompt: false };
|
|
2868
|
+
if (!sessionId) return { messages: [], items: [], hasQueuedPrompt: false };
|
|
2869
|
+
if (!this.ownsSession(sessionId)) {
|
|
2870
|
+
return { messages: [], items: [], hasQueuedPrompt: false };
|
|
2871
|
+
}
|
|
2589
2872
|
const entry = this.resolveEntry(sessionId);
|
|
2590
|
-
if (!entry) return { messages: [], hasQueuedPrompt: false };
|
|
2873
|
+
if (!entry) return { messages: [], items: [], hasQueuedPrompt: false };
|
|
2591
2874
|
const drained = entry.midTurnMessageQueue.splice(0);
|
|
2592
2875
|
if (drained.length > 0) {
|
|
2593
2876
|
for (const item of drained) {
|
|
@@ -2600,6 +2883,64 @@ var BridgeClient = class {
|
|
|
2600
2883
|
);
|
|
2601
2884
|
}
|
|
2602
2885
|
}
|
|
2886
|
+
const mediaMemo = /* @__PURE__ */ new Map();
|
|
2887
|
+
const serializedMediaIds = /* @__PURE__ */ new Set();
|
|
2888
|
+
const items = [];
|
|
2889
|
+
try {
|
|
2890
|
+
for (const item of drained) {
|
|
2891
|
+
let degraded = 0;
|
|
2892
|
+
const planned = (item.content ?? []).filter((block) => {
|
|
2893
|
+
if (!isSessionMediaReference(block)) return true;
|
|
2894
|
+
if (serializedMediaIds.has(block.mediaId)) {
|
|
2895
|
+
degraded += 1;
|
|
2896
|
+
return false;
|
|
2897
|
+
}
|
|
2898
|
+
serializedMediaIds.add(block.mediaId);
|
|
2899
|
+
return true;
|
|
2900
|
+
});
|
|
2901
|
+
let resolvedBlocks;
|
|
2902
|
+
let mediaReferences;
|
|
2903
|
+
try {
|
|
2904
|
+
resolvedBlocks = await entry.media.resolveContent(planned, mediaMemo);
|
|
2905
|
+
mediaReferences = planned.filter(isSessionMediaReference);
|
|
2906
|
+
} catch (error) {
|
|
2907
|
+
if (!(error instanceof SessionMediaReferenceError)) throw error;
|
|
2908
|
+
writeStderrLine(
|
|
2909
|
+
`[mid-turn] session=${JSON.stringify(entry.sessionId)} degraded media for message ${JSON.stringify(item.messageId)}: ${JSON.stringify(error instanceof Error ? error.message : String(error))}`
|
|
2910
|
+
);
|
|
2911
|
+
const perBlock = await entry.media.resolveContentDegrading(
|
|
2912
|
+
planned,
|
|
2913
|
+
mediaMemo
|
|
2914
|
+
);
|
|
2915
|
+
resolvedBlocks = perBlock.resolvedBlocks;
|
|
2916
|
+
mediaReferences = perBlock.retainedBlocks.filter(
|
|
2917
|
+
isSessionMediaReference
|
|
2918
|
+
);
|
|
2919
|
+
degraded += perBlock.degraded;
|
|
2920
|
+
}
|
|
2921
|
+
let content = [
|
|
2922
|
+
...item.text ? [{ type: "text", text: item.text }] : [],
|
|
2923
|
+
...resolvedBlocks
|
|
2924
|
+
];
|
|
2925
|
+
if (degraded > 0) content = withMediaDegradationMarker(content);
|
|
2926
|
+
items.push({
|
|
2927
|
+
messageId: item.messageId,
|
|
2928
|
+
displayText: item.text,
|
|
2929
|
+
content,
|
|
2930
|
+
...mediaReferences.length > 0 ? { mediaReferences } : {}
|
|
2931
|
+
});
|
|
2932
|
+
}
|
|
2933
|
+
} catch (error) {
|
|
2934
|
+
const requeued = new Set(drained.map((queued) => queued.messageId));
|
|
2935
|
+
const ring = entry.settledMidTurnMessageIds;
|
|
2936
|
+
const kept = ring.filter((id) => !requeued.has(id));
|
|
2937
|
+
ring.splice(0, ring.length, ...kept);
|
|
2938
|
+
entry.midTurnMessageQueue.unshift(...drained);
|
|
2939
|
+
writeStderrLine(
|
|
2940
|
+
`[mid-turn] session=${JSON.stringify(entry.sessionId)} drain failed, requeued ${drained.length} message(s): ${JSON.stringify(error instanceof Error ? error.message : String(error))}`
|
|
2941
|
+
);
|
|
2942
|
+
throw error;
|
|
2943
|
+
}
|
|
2603
2944
|
const echoed = drained.filter((item) => !item.queueOnly);
|
|
2604
2945
|
const messages = drained.map((item) => item.text);
|
|
2605
2946
|
const hasQueuedPrompt = entry.pendingPromptList.some(
|
|
@@ -2612,14 +2953,21 @@ var BridgeClient = class {
|
|
|
2612
2953
|
data: {
|
|
2613
2954
|
sessionId: entry.sessionId,
|
|
2614
2955
|
messages: echoed.map((item) => item.text),
|
|
2615
|
-
messageIds: echoed.map((item) => item.messageId)
|
|
2956
|
+
messageIds: echoed.map((item) => item.messageId),
|
|
2957
|
+
// Carry the structured `items` twin (content blocks per message) so
|
|
2958
|
+
// the browser-side echo renderer can show attached images alongside
|
|
2959
|
+
// the message text. Older consumers that don't read this field keep
|
|
2960
|
+
// working unchanged.
|
|
2961
|
+
items: echoed.map((item) => ({
|
|
2962
|
+
...item.content && item.content.length > 0 ? { content: item.content } : {}
|
|
2963
|
+
}))
|
|
2616
2964
|
}
|
|
2617
2965
|
});
|
|
2618
2966
|
writeStderrLine(
|
|
2619
2967
|
published ? `[mid-turn] session=${entry.sessionId} drained=${messages.length} echoed=${echoed.length} injected into running turn` : `[mid-turn] session=${entry.sessionId} drained=${messages.length} echoed=${echoed.length} echo frame dropped (bus closed); reconciliation required`
|
|
2620
2968
|
);
|
|
2621
2969
|
}
|
|
2622
|
-
return { messages, hasQueuedPrompt };
|
|
2970
|
+
return { messages, items, hasQueuedPrompt };
|
|
2623
2971
|
}
|
|
2624
2972
|
async handleExternalToolGuardPrepare(params) {
|
|
2625
2973
|
if (!this.externalToolGuard) {
|
|
@@ -3146,6 +3494,7 @@ var BridgeClient = class {
|
|
|
3146
3494
|
return;
|
|
3147
3495
|
const entry = this.resolveEntry(sessionId2);
|
|
3148
3496
|
if (!entry) return;
|
|
3497
|
+
this.onSessionCatalogChanged?.();
|
|
3149
3498
|
try {
|
|
3150
3499
|
entry.events.publish({
|
|
3151
3500
|
type: "session_metadata_updated",
|
|
@@ -3588,20 +3937,20 @@ var BridgeClient = class {
|
|
|
3588
3937
|
}
|
|
3589
3938
|
let realTarget = params.path;
|
|
3590
3939
|
try {
|
|
3591
|
-
realTarget = await
|
|
3940
|
+
realTarget = await fs2.realpath(params.path);
|
|
3592
3941
|
} catch (err) {
|
|
3593
3942
|
const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
|
|
3594
3943
|
if (code !== "ENOENT") throw err;
|
|
3595
3944
|
try {
|
|
3596
|
-
const linkTarget = await
|
|
3597
|
-
realTarget =
|
|
3945
|
+
const linkTarget = await fs2.readlink(params.path);
|
|
3946
|
+
realTarget = path2.resolve(path2.dirname(params.path), linkTarget);
|
|
3598
3947
|
} catch {
|
|
3599
3948
|
}
|
|
3600
3949
|
}
|
|
3601
|
-
const tmp = `${realTarget}.${process.pid}.${Date.now()}.${
|
|
3950
|
+
const tmp = `${realTarget}.${process.pid}.${Date.now()}.${randomUUID2()}.tmp`;
|
|
3602
3951
|
let preserveMode;
|
|
3603
3952
|
try {
|
|
3604
|
-
const targetStat = await
|
|
3953
|
+
const targetStat = await fs2.stat(realTarget);
|
|
3605
3954
|
preserveMode = {
|
|
3606
3955
|
mode: targetStat.mode & 4095,
|
|
3607
3956
|
uid: targetStat.uid,
|
|
@@ -3612,20 +3961,20 @@ var BridgeClient = class {
|
|
|
3612
3961
|
if (code !== "ENOENT") throw err;
|
|
3613
3962
|
}
|
|
3614
3963
|
try {
|
|
3615
|
-
await
|
|
3964
|
+
await fs2.writeFile(tmp, params.content, {
|
|
3616
3965
|
encoding: "utf8",
|
|
3617
3966
|
flag: "wx",
|
|
3618
3967
|
mode: preserveMode?.mode ?? 384
|
|
3619
3968
|
});
|
|
3620
3969
|
if (preserveMode) {
|
|
3621
|
-
await
|
|
3970
|
+
await fs2.chmod(tmp, preserveMode.mode).catch(() => {
|
|
3622
3971
|
});
|
|
3623
|
-
await
|
|
3972
|
+
await fs2.chown(tmp, preserveMode.uid, preserveMode.gid).catch(() => {
|
|
3624
3973
|
});
|
|
3625
3974
|
}
|
|
3626
|
-
await
|
|
3975
|
+
await fs2.rename(tmp, realTarget);
|
|
3627
3976
|
} catch (err) {
|
|
3628
|
-
await
|
|
3977
|
+
await fs2.unlink(tmp).catch(() => {
|
|
3629
3978
|
});
|
|
3630
3979
|
throw err;
|
|
3631
3980
|
}
|
|
@@ -3655,7 +4004,7 @@ var BridgeClient = class {
|
|
|
3655
4004
|
);
|
|
3656
4005
|
}
|
|
3657
4006
|
const READ_FILE_SIZE_CAP = 100 * 1024 * 1024;
|
|
3658
|
-
const stats = await
|
|
4007
|
+
const stats = await fs2.stat(params.path);
|
|
3659
4008
|
if (!stats.isFile()) {
|
|
3660
4009
|
throw new Error(
|
|
3661
4010
|
`readTextFile: ${params.path} is not a regular file (reported as ${describeStatKind(stats)}). Pipe / device / proc-like inputs can produce unbounded data and aren't supported by the bridge fs proxy.`
|
|
@@ -3666,7 +4015,7 @@ var BridgeClient = class {
|
|
|
3666
4015
|
`readTextFile: ${params.path} is ${stats.size} bytes, exceeds the ${READ_FILE_SIZE_CAP}-byte daemon cap. Tail/grep externally and feed the relevant slice instead.`
|
|
3667
4016
|
);
|
|
3668
4017
|
}
|
|
3669
|
-
const content = await
|
|
4018
|
+
const content = await fs2.readFile(params.path, "utf8");
|
|
3670
4019
|
if (typeof params.line === "number" || typeof params.limit === "number") {
|
|
3671
4020
|
const startLine = params.line ?? 1;
|
|
3672
4021
|
const start = startLine > 0 ? startLine - 1 : 0;
|
|
@@ -3868,8 +4217,8 @@ var GenerationStreamQueue = class {
|
|
|
3868
4217
|
// packages/acp-bridge/src/sessionArtifacts.ts
|
|
3869
4218
|
init_esbuild_shims();
|
|
3870
4219
|
import { createHash } from "node:crypto";
|
|
3871
|
-
import { constants as fsConstants, promises as
|
|
3872
|
-
import
|
|
4220
|
+
import { constants as fsConstants, promises as fs3 } from "node:fs";
|
|
4221
|
+
import path3 from "node:path";
|
|
3873
4222
|
var SOURCE_RESERVATIONS = {
|
|
3874
4223
|
tool: 100,
|
|
3875
4224
|
client: 50,
|
|
@@ -4940,7 +5289,7 @@ var SessionArtifactStore = class {
|
|
|
4940
5289
|
}
|
|
4941
5290
|
getRealWorkspaceCwd() {
|
|
4942
5291
|
if (!this.realWorkspaceCwdPromise) {
|
|
4943
|
-
const promise =
|
|
5292
|
+
const promise = fs3.realpath(this.workspaceCwd).catch((error) => {
|
|
4944
5293
|
if (this.realWorkspaceCwdPromise === promise) {
|
|
4945
5294
|
this.realWorkspaceCwdPromise = void 0;
|
|
4946
5295
|
}
|
|
@@ -5060,8 +5409,15 @@ function mergeBatchArtifact(existing, next) {
|
|
|
5060
5409
|
delete merged.workspacePath;
|
|
5061
5410
|
return merged;
|
|
5062
5411
|
}
|
|
5412
|
+
const refreshDisplay = existing.storage === "workspace" && next.storage === "workspace" && shouldRefreshWorkspaceDisplay(next, existing);
|
|
5063
5413
|
return {
|
|
5064
5414
|
...existing,
|
|
5415
|
+
title: refreshDisplay ? next.title : existing.title,
|
|
5416
|
+
description: refreshDisplay ? next.description ?? existing.description : existing.description,
|
|
5417
|
+
toolName: refreshDisplay ? next.toolName : existing.toolName,
|
|
5418
|
+
source: refreshDisplay ? next.source : existing.source,
|
|
5419
|
+
hookEventName: refreshDisplay ? next.hookEventName : existing.hookEventName,
|
|
5420
|
+
toolCallId: refreshDisplay ? next.toolCallId : existing.toolCallId,
|
|
5065
5421
|
status: next.status,
|
|
5066
5422
|
sizeBytes: mergeSizeBytes(existing, next),
|
|
5067
5423
|
metadata: mergeMetadata(existing, next),
|
|
@@ -5108,6 +5464,13 @@ function mergeArtifact(existing, incoming) {
|
|
|
5108
5464
|
next.description = incoming.description;
|
|
5109
5465
|
delete next.workspacePath;
|
|
5110
5466
|
delete next.hideWorkspacePath;
|
|
5467
|
+
} else if (existing.storage === "workspace" && incoming.storage === "workspace" && shouldRefreshWorkspaceDisplay(incoming, existing)) {
|
|
5468
|
+
next.title = incoming.title;
|
|
5469
|
+
next.description = incoming.description ?? existing.description;
|
|
5470
|
+
next.toolCallId = incoming.toolCallId;
|
|
5471
|
+
next.toolName = incoming.toolName;
|
|
5472
|
+
next.source = incoming.source;
|
|
5473
|
+
next.hookEventName = incoming.hookEventName;
|
|
5111
5474
|
}
|
|
5112
5475
|
const changed = !publicArtifactsEqual(
|
|
5113
5476
|
toPublicArtifact(existing),
|
|
@@ -5123,6 +5486,16 @@ function shouldRecordEphemeralUnpin(existing, incoming) {
|
|
|
5123
5486
|
return incoming.retentionExplicit && incoming.retention === "ephemeral" && (existing.retention !== "ephemeral" || existing.persistedAt !== void 0 || existing.durableTombstoneRequired === true);
|
|
5124
5487
|
}
|
|
5125
5488
|
__name(shouldRecordEphemeralUnpin, "shouldRecordEphemeralUnpin");
|
|
5489
|
+
function shouldRefreshWorkspaceDisplay(incoming, existing) {
|
|
5490
|
+
if (incoming.toolName === "record_artifact" && incoming.source !== "hook") {
|
|
5491
|
+
return true;
|
|
5492
|
+
}
|
|
5493
|
+
if (!incoming.toolName) {
|
|
5494
|
+
return true;
|
|
5495
|
+
}
|
|
5496
|
+
return incoming.toolName === existing.toolName && incoming.source === existing.source && incoming.hookEventName === existing.hookEventName;
|
|
5497
|
+
}
|
|
5498
|
+
__name(shouldRefreshWorkspaceDisplay, "shouldRefreshWorkspaceDisplay");
|
|
5126
5499
|
function publicArtifactsEqual(a, b) {
|
|
5127
5500
|
return a.id === b.id && a.kind === b.kind && a.storage === b.storage && a.source === b.source && a.status === b.status && a.title === b.title && a.description === b.description && a.workspacePath === b.workspacePath && a.managedId === b.managedId && a.url === b.url && a.mimeType === b.mimeType && a.sizeBytes === b.sizeBytes && metadataEqual(a.metadata, b.metadata) && a.retention === b.retention && a.restoreState === b.restoreState && a.persistenceWarning === b.persistenceWarning && a.persistedAt === b.persistedAt && a.clientRetained === b.clientRetained && a.createdAt === b.createdAt && a.updatedAt === b.updatedAt && a.toolCallId === b.toolCallId && a.toolName === b.toolName && a.hookEventName === b.hookEventName && a.clientId === b.clientId;
|
|
5128
5501
|
}
|
|
@@ -5575,7 +5948,7 @@ function buildIdentityKey(input) {
|
|
|
5575
5948
|
}
|
|
5576
5949
|
__name(buildIdentityKey, "buildIdentityKey");
|
|
5577
5950
|
function managedIdForWorkspacePath(workspaceCwd, workspacePath) {
|
|
5578
|
-
return createHash("sha1").update(
|
|
5951
|
+
return createHash("sha1").update(path3.resolve(workspaceCwd, workspacePath)).digest("hex").slice(0, 16);
|
|
5579
5952
|
}
|
|
5580
5953
|
__name(managedIdForWorkspacePath, "managedIdForWorkspacePath");
|
|
5581
5954
|
function normalizeString(value, field, maxLength, required) {
|
|
@@ -5622,7 +5995,7 @@ __name(normalizeString, "normalizeString");
|
|
|
5622
5995
|
function normalizeManagedId(value) {
|
|
5623
5996
|
const managedId = normalizeString(value, "managedId", 200, false);
|
|
5624
5997
|
if (!managedId) return void 0;
|
|
5625
|
-
if (managedId.includes("/") || managedId.includes("\\") || managedId.includes("..") ||
|
|
5998
|
+
if (managedId.includes("/") || managedId.includes("\\") || managedId.includes("..") || path3.isAbsolute(managedId) || path3.win32.isAbsolute(managedId)) {
|
|
5626
5999
|
throw new SessionArtifactValidationError(
|
|
5627
6000
|
"managedId must be an opaque managed resource id",
|
|
5628
6001
|
"managedId"
|
|
@@ -5656,21 +6029,21 @@ function hasUnsafeDisplayPayload(value) {
|
|
|
5656
6029
|
__name(hasUnsafeDisplayPayload, "hasUnsafeDisplayPayload");
|
|
5657
6030
|
function normalizeWorkspacePath(raw, workspaceCwd) {
|
|
5658
6031
|
const trimmed = normalizeString(raw, "workspacePath", 500, true);
|
|
5659
|
-
if (
|
|
6032
|
+
if (path3.isAbsolute(trimmed)) {
|
|
5660
6033
|
throw new SessionArtifactValidationError(
|
|
5661
6034
|
"workspacePath must be relative to the workspace",
|
|
5662
6035
|
"workspacePath"
|
|
5663
6036
|
);
|
|
5664
6037
|
}
|
|
5665
|
-
const absolute =
|
|
5666
|
-
const relative =
|
|
6038
|
+
const absolute = path3.resolve(workspaceCwd, trimmed);
|
|
6039
|
+
const relative = path3.relative(workspaceCwd, absolute);
|
|
5667
6040
|
if (!relative || isOutsidePath(relative)) {
|
|
5668
6041
|
throw new SessionArtifactValidationError(
|
|
5669
6042
|
"workspacePath must stay inside the workspace",
|
|
5670
6043
|
"workspacePath"
|
|
5671
6044
|
);
|
|
5672
6045
|
}
|
|
5673
|
-
return relative.split(
|
|
6046
|
+
return relative.split(path3.sep).join("/");
|
|
5674
6047
|
}
|
|
5675
6048
|
__name(normalizeWorkspacePath, "normalizeWorkspacePath");
|
|
5676
6049
|
function normalizeArtifactUrl(raw, allowFile) {
|
|
@@ -5871,7 +6244,7 @@ __name(normalizeSizeBytes, "normalizeSizeBytes");
|
|
|
5871
6244
|
function inferKind(input) {
|
|
5872
6245
|
if (input.storage === "published") return "html";
|
|
5873
6246
|
if (input.url) return "link";
|
|
5874
|
-
const ext = input.workspacePath ?
|
|
6247
|
+
const ext = input.workspacePath ? path3.extname(input.workspacePath).toLowerCase() : "";
|
|
5875
6248
|
if (ext === ".html" || ext === ".htm") return "html";
|
|
5876
6249
|
if ([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"].includes(ext)) {
|
|
5877
6250
|
return "image";
|
|
@@ -5885,15 +6258,15 @@ function inferKind(input) {
|
|
|
5885
6258
|
__name(inferKind, "inferKind");
|
|
5886
6259
|
async function getWorkspaceStatus(workspacePath, realWorkspaceCwd, expected, options = { hashContent: true }) {
|
|
5887
6260
|
const realWorkspace = await realWorkspaceCwd;
|
|
5888
|
-
const absolutePath =
|
|
6261
|
+
const absolutePath = path3.resolve(realWorkspace, workspacePath);
|
|
5889
6262
|
try {
|
|
5890
|
-
const realPath = await
|
|
5891
|
-
const relative =
|
|
6263
|
+
const realPath = await fs3.realpath(absolutePath);
|
|
6264
|
+
const relative = path3.relative(realWorkspace, realPath);
|
|
5892
6265
|
if (!relative || isOutsidePath(relative)) {
|
|
5893
6266
|
return { status: "missing", escaped: true };
|
|
5894
6267
|
}
|
|
5895
|
-
const preOpenStat = await
|
|
5896
|
-
const handle = await
|
|
6268
|
+
const preOpenStat = await fs3.lstat(realPath);
|
|
6269
|
+
const handle = await fs3.open(
|
|
5897
6270
|
realPath,
|
|
5898
6271
|
fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW
|
|
5899
6272
|
);
|
|
@@ -6007,14 +6380,14 @@ function isWorkspaceContentChanged(artifact, status) {
|
|
|
6007
6380
|
__name(isWorkspaceContentChanged, "isWorkspaceContentChanged");
|
|
6008
6381
|
async function danglingSymlinkEscapesWorkspace(absolutePath, realWorkspace) {
|
|
6009
6382
|
try {
|
|
6010
|
-
const stat = await
|
|
6383
|
+
const stat = await fs3.lstat(absolutePath);
|
|
6011
6384
|
if (!stat.isSymbolicLink()) {
|
|
6012
6385
|
return false;
|
|
6013
6386
|
}
|
|
6014
|
-
const target = await
|
|
6015
|
-
const parent = await
|
|
6016
|
-
const targetPath =
|
|
6017
|
-
return isOutsidePath(
|
|
6387
|
+
const target = await fs3.readlink(absolutePath);
|
|
6388
|
+
const parent = await fs3.realpath(path3.dirname(absolutePath));
|
|
6389
|
+
const targetPath = path3.resolve(parent, target);
|
|
6390
|
+
return isOutsidePath(path3.relative(realWorkspace, targetPath));
|
|
6018
6391
|
} catch (error) {
|
|
6019
6392
|
if (isNotFoundError(error)) {
|
|
6020
6393
|
return false;
|
|
@@ -6045,7 +6418,7 @@ function isNoFollowSymlinkError(error) {
|
|
|
6045
6418
|
}
|
|
6046
6419
|
__name(isNoFollowSymlinkError, "isNoFollowSymlinkError");
|
|
6047
6420
|
function isOutsidePath(relative) {
|
|
6048
|
-
return relative === ".." || relative.startsWith(`..${
|
|
6421
|
+
return relative === ".." || relative.startsWith(`..${path3.sep}`) || path3.isAbsolute(relative);
|
|
6049
6422
|
}
|
|
6050
6423
|
__name(isOutsidePath, "isOutsidePath");
|
|
6051
6424
|
|
|
@@ -6678,13 +7051,20 @@ function broadcastPromptCancelledOnce(entry, sessionId, promptId, originatorClie
|
|
|
6678
7051
|
__name(broadcastPromptCancelledOnce, "broadcastPromptCancelledOnce");
|
|
6679
7052
|
function broadcastTurnComplete(entry, sessionId, promptResult, promptId, originatorClientId, mutateTurnState) {
|
|
6680
7053
|
try {
|
|
7054
|
+
const meta = promptResult["_meta"] && typeof promptResult["_meta"] === "object" ? promptResult["_meta"] : void 0;
|
|
7055
|
+
const rawBranchPoint = meta?.["qwen.branchPoint"] && typeof meta["qwen.branchPoint"] === "object" ? meta["qwen.branchPoint"] : void 0;
|
|
7056
|
+
const branchPoint = promptResult.stopReason === "end_turn" && typeof rawBranchPoint?.["assistantRecordUuid"] === "string" && CHAT_RECORD_UUID_RE.test(rawBranchPoint["assistantRecordUuid"]) && typeof rawBranchPoint["checkpointUuid"] === "string" && CHAT_RECORD_UUID_RE.test(rawBranchPoint["checkpointUuid"]) ? {
|
|
7057
|
+
assistantRecordUuid: rawBranchPoint["assistantRecordUuid"],
|
|
7058
|
+
checkpointUuid: rawBranchPoint["checkpointUuid"]
|
|
7059
|
+
} : void 0;
|
|
6681
7060
|
const published = entry.events.publish({
|
|
6682
7061
|
type: "turn_complete",
|
|
6683
7062
|
...promptId ? { promptId } : {},
|
|
6684
7063
|
data: {
|
|
6685
7064
|
sessionId,
|
|
6686
7065
|
stopReason: promptResult.stopReason ?? "end_turn",
|
|
6687
|
-
...promptId ? { promptId } : {}
|
|
7066
|
+
...promptId ? { promptId } : {},
|
|
7067
|
+
...branchPoint ? { branchPoint } : {}
|
|
6688
7068
|
},
|
|
6689
7069
|
...originatorClientId ? { originatorClientId } : {}
|
|
6690
7070
|
});
|
|
@@ -6845,6 +7225,57 @@ function broadcastTurnError(entry, sessionId, err, promptId, originatorClientId,
|
|
|
6845
7225
|
}
|
|
6846
7226
|
}
|
|
6847
7227
|
__name(broadcastTurnError, "broadcastTurnError");
|
|
7228
|
+
var TERMINAL_TURN_STATUS_OVERLAY_LIMIT = 64;
|
|
7229
|
+
function truncateTurnText(text) {
|
|
7230
|
+
const truncated = text.length > TURN_RESULT_TEXT_MAX_CHARS;
|
|
7231
|
+
return {
|
|
7232
|
+
text: truncated ? text.slice(0, TURN_RESULT_TEXT_MAX_CHARS) : text,
|
|
7233
|
+
truncated
|
|
7234
|
+
};
|
|
7235
|
+
}
|
|
7236
|
+
__name(truncateTurnText, "truncateTurnText");
|
|
7237
|
+
function rememberTerminalTurnStatus(entry, pending, terminal) {
|
|
7238
|
+
const promptText = truncateTurnText(pending.text);
|
|
7239
|
+
const shared = {
|
|
7240
|
+
sessionId: entry.sessionId,
|
|
7241
|
+
promptId: pending.promptId,
|
|
7242
|
+
promptText: promptText.text,
|
|
7243
|
+
...promptText.truncated ? { promptTextTruncated: true } : {},
|
|
7244
|
+
queuedAt: pending.queuedAt,
|
|
7245
|
+
...pending.startedAt !== void 0 ? { startedAt: pending.startedAt } : {},
|
|
7246
|
+
endedAt: Date.now(),
|
|
7247
|
+
...pending.originatorClientId !== void 0 ? { originatorClientId: pending.originatorClientId } : {}
|
|
7248
|
+
};
|
|
7249
|
+
const status = terminal.kind === "complete" ? {
|
|
7250
|
+
...shared,
|
|
7251
|
+
state: terminal.result.stopReason === "cancelled" ? "cancelled" : "completed",
|
|
7252
|
+
...terminal.result.stopReason !== void 0 ? { stopReason: terminal.result.stopReason } : {}
|
|
7253
|
+
} : terminal.kind === "cancelled" ? { ...shared, state: "cancelled", stopReason: "cancelled" } : {
|
|
7254
|
+
...shared,
|
|
7255
|
+
state: "error",
|
|
7256
|
+
error: normalizeTurnResultError(terminal.err)
|
|
7257
|
+
};
|
|
7258
|
+
entry.terminalTurnStatuses.set(pending.promptId, status);
|
|
7259
|
+
entry.enrichedTerminalPromptIds.delete(pending.promptId);
|
|
7260
|
+
while (entry.terminalTurnStatuses.size > TERMINAL_TURN_STATUS_OVERLAY_LIMIT) {
|
|
7261
|
+
const oldest2 = entry.terminalTurnStatuses.keys().next().value;
|
|
7262
|
+
if (oldest2 === void 0) break;
|
|
7263
|
+
entry.terminalTurnStatuses.delete(oldest2);
|
|
7264
|
+
entry.enrichedTerminalPromptIds.delete(oldest2);
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
__name(rememberTerminalTurnStatus, "rememberTerminalTurnStatus");
|
|
7268
|
+
function rememberEnrichedTerminalTurnStatus(entry, promptId, status) {
|
|
7269
|
+
entry.terminalTurnStatuses.set(promptId, status);
|
|
7270
|
+
entry.enrichedTerminalPromptIds.add(promptId);
|
|
7271
|
+
while (entry.terminalTurnStatuses.size > TERMINAL_TURN_STATUS_OVERLAY_LIMIT) {
|
|
7272
|
+
const oldest2 = entry.terminalTurnStatuses.keys().next().value;
|
|
7273
|
+
if (oldest2 === void 0) break;
|
|
7274
|
+
entry.terminalTurnStatuses.delete(oldest2);
|
|
7275
|
+
entry.enrichedTerminalPromptIds.delete(oldest2);
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7278
|
+
__name(rememberEnrichedTerminalTurnStatus, "rememberEnrichedTerminalTurnStatus");
|
|
6848
7279
|
function publishPromptTerminal(entry, pendingEntry, terminal) {
|
|
6849
7280
|
if (pendingEntry.terminalPublished) {
|
|
6850
7281
|
writeServeDebugLine(
|
|
@@ -6853,6 +7284,7 @@ function publishPromptTerminal(entry, pendingEntry, terminal) {
|
|
|
6853
7284
|
return;
|
|
6854
7285
|
}
|
|
6855
7286
|
pendingEntry.terminalPublished = true;
|
|
7287
|
+
rememberTerminalTurnStatus(entry, pendingEntry, terminal);
|
|
6856
7288
|
const originatorClientId = pendingEntry.originatorClientId;
|
|
6857
7289
|
const mutateTurnState = pendingEntry.state === "running";
|
|
6858
7290
|
if (!mutateTurnState && entry.turnErrorEvent) {
|
|
@@ -6920,16 +7352,109 @@ function extractPromptText(prompt) {
|
|
|
6920
7352
|
if (!Array.isArray(prompt)) return "";
|
|
6921
7353
|
let hasImage = false;
|
|
6922
7354
|
for (const block of prompt) {
|
|
6923
|
-
|
|
7355
|
+
const record = block;
|
|
7356
|
+
if (record["type"] === "image") {
|
|
6924
7357
|
hasImage = true;
|
|
6925
7358
|
}
|
|
6926
|
-
if (
|
|
6927
|
-
return
|
|
7359
|
+
if (record["type"] === "text" && typeof record["text"] === "string" && record["text"].length > 0) {
|
|
7360
|
+
return record["text"];
|
|
6928
7361
|
}
|
|
6929
7362
|
}
|
|
6930
7363
|
return hasImage ? "[image]" : "";
|
|
6931
7364
|
}
|
|
6932
7365
|
__name(extractPromptText, "extractPromptText");
|
|
7366
|
+
function liveTurnStatus(sessionId, pending) {
|
|
7367
|
+
const promptText = truncateTurnText(pending.text);
|
|
7368
|
+
return {
|
|
7369
|
+
sessionId,
|
|
7370
|
+
state: pending.state === "running" ? "running" : "queued",
|
|
7371
|
+
promptId: pending.promptId,
|
|
7372
|
+
promptText: promptText.text,
|
|
7373
|
+
...promptText.truncated ? { promptTextTruncated: true } : {},
|
|
7374
|
+
queuedAt: pending.queuedAt,
|
|
7375
|
+
...pending.startedAt !== void 0 ? { startedAt: pending.startedAt } : {},
|
|
7376
|
+
...pending.originatorClientId !== void 0 ? { originatorClientId: pending.originatorClientId } : {}
|
|
7377
|
+
};
|
|
7378
|
+
}
|
|
7379
|
+
__name(liveTurnStatus, "liveTurnStatus");
|
|
7380
|
+
function findLiveTurnStatus(entry, promptId) {
|
|
7381
|
+
const live = entry.pendingPromptList.filter(
|
|
7382
|
+
(pending) => !pending.terminalPublished && (!pending.removed || pending.state === "running")
|
|
7383
|
+
);
|
|
7384
|
+
if (promptId !== void 0) {
|
|
7385
|
+
const match = live.find((pending) => pending.promptId === promptId);
|
|
7386
|
+
return match ? liveTurnStatus(entry.sessionId, match) : void 0;
|
|
7387
|
+
}
|
|
7388
|
+
const running = live.find((pending) => pending.state === "running");
|
|
7389
|
+
if (running) return liveTurnStatus(entry.sessionId, running);
|
|
7390
|
+
const queued = live.find((pending) => pending.state === "queued");
|
|
7391
|
+
return queued ? liveTurnStatus(entry.sessionId, queued) : void 0;
|
|
7392
|
+
}
|
|
7393
|
+
__name(findLiveTurnStatus, "findLiveTurnStatus");
|
|
7394
|
+
function settledTurnStatus(sessionId, record) {
|
|
7395
|
+
return {
|
|
7396
|
+
sessionId,
|
|
7397
|
+
state: record.state,
|
|
7398
|
+
promptId: record.promptId,
|
|
7399
|
+
...record.stopReason !== void 0 ? { stopReason: record.stopReason } : {},
|
|
7400
|
+
...record.error !== void 0 ? { error: record.error } : {},
|
|
7401
|
+
...record.startedAt !== void 0 ? { startedAt: record.startedAt } : {},
|
|
7402
|
+
endedAt: record.endedAt,
|
|
7403
|
+
...record.promptText !== void 0 ? { promptText: record.promptText } : {},
|
|
7404
|
+
...record.promptTextTruncated !== void 0 ? { promptTextTruncated: record.promptTextTruncated } : {},
|
|
7405
|
+
...record.resultText !== void 0 ? { resultText: record.resultText } : {},
|
|
7406
|
+
...record.resultTruncated !== void 0 ? { resultTruncated: record.resultTruncated } : {},
|
|
7407
|
+
...record.resultTruncated === true ? { resultCode: record.resultCode ?? TURN_RESULT_CODE_TEXT_TRUNCATED } : {},
|
|
7408
|
+
...record.originatorClientId !== void 0 ? { originatorClientId: record.originatorClientId } : {}
|
|
7409
|
+
};
|
|
7410
|
+
}
|
|
7411
|
+
__name(settledTurnStatus, "settledTurnStatus");
|
|
7412
|
+
function enrichTerminalTurnStatus(terminal, persisted) {
|
|
7413
|
+
return {
|
|
7414
|
+
...terminal,
|
|
7415
|
+
// The bridge's display projection is trusted; the child-recorded text
|
|
7416
|
+
// only backfills when the terminal has none, so hidden channel context
|
|
7417
|
+
// the child derived from raw blocks never replaces it.
|
|
7418
|
+
...terminal.promptText === void 0 && persisted.promptText !== void 0 ? { promptText: persisted.promptText } : {},
|
|
7419
|
+
...terminal.promptTextTruncated === void 0 && persisted.promptTextTruncated !== void 0 ? { promptTextTruncated: persisted.promptTextTruncated } : {},
|
|
7420
|
+
...persisted.resultText !== void 0 ? { resultText: persisted.resultText } : {},
|
|
7421
|
+
...persisted.resultTruncated !== void 0 ? { resultTruncated: persisted.resultTruncated } : {},
|
|
7422
|
+
...persisted.resultCode !== void 0 ? { resultCode: persisted.resultCode } : {},
|
|
7423
|
+
...terminal.originatorClientId === void 0 && persisted.originatorClientId !== void 0 ? { originatorClientId: persisted.originatorClientId } : {}
|
|
7424
|
+
};
|
|
7425
|
+
}
|
|
7426
|
+
__name(enrichTerminalTurnStatus, "enrichTerminalTurnStatus");
|
|
7427
|
+
function mergeTerminalWithPersisted(terminal, persisted) {
|
|
7428
|
+
if (terminal.state === "error" && persisted.state !== "error") {
|
|
7429
|
+
return {
|
|
7430
|
+
...persisted,
|
|
7431
|
+
...terminal.promptText !== void 0 ? { promptText: terminal.promptText } : {},
|
|
7432
|
+
...terminal.promptTextTruncated !== void 0 ? { promptTextTruncated: terminal.promptTextTruncated } : {}
|
|
7433
|
+
};
|
|
7434
|
+
}
|
|
7435
|
+
return enrichTerminalTurnStatus(terminal, persisted);
|
|
7436
|
+
}
|
|
7437
|
+
__name(mergeTerminalWithPersisted, "mergeTerminalWithPersisted");
|
|
7438
|
+
function latestTerminalTurnStatus(entry) {
|
|
7439
|
+
let latest;
|
|
7440
|
+
for (const status of entry.terminalTurnStatuses.values()) {
|
|
7441
|
+
if ((status.endedAt ?? 0) >= (latest?.endedAt ?? 0)) latest = status;
|
|
7442
|
+
}
|
|
7443
|
+
return latest;
|
|
7444
|
+
}
|
|
7445
|
+
__name(latestTerminalTurnStatus, "latestTerminalTurnStatus");
|
|
7446
|
+
function extractMediaBlocks(prompt) {
|
|
7447
|
+
if (!Array.isArray(prompt)) return void 0;
|
|
7448
|
+
const media = [];
|
|
7449
|
+
for (const block of prompt) {
|
|
7450
|
+
if (!block || typeof block !== "object") continue;
|
|
7451
|
+
if (block.type === "image" || block.type === "audio") {
|
|
7452
|
+
media.push(block);
|
|
7453
|
+
}
|
|
7454
|
+
}
|
|
7455
|
+
return media.length > 0 ? media : void 0;
|
|
7456
|
+
}
|
|
7457
|
+
__name(extractMediaBlocks, "extractMediaBlocks");
|
|
6933
7458
|
var DEFAULT_INIT_TIMEOUT_MS = 1e4;
|
|
6934
7459
|
var PERSIST_TIMEOUT_MS = 5e3;
|
|
6935
7460
|
var MAX_PARENT_PERSIST_ATTEMPTS = 3;
|
|
@@ -6947,13 +7472,25 @@ var MAX_EMPTY_TRANSCRIPT_PAGES = 20;
|
|
|
6947
7472
|
var SHELL_COMMAND_TIMEOUT_MS = 12e4;
|
|
6948
7473
|
var MAX_SHELL_OUTPUT_FOR_HISTORY = 1e4;
|
|
6949
7474
|
var MAX_MID_TURN_QUEUE_DEPTH = 20;
|
|
7475
|
+
var inlineMediaBlockBytes = /* @__PURE__ */ __name((blocks) => {
|
|
7476
|
+
let total = 0;
|
|
7477
|
+
for (const block of blocks) {
|
|
7478
|
+
if (block.type === "image" && "data" in block) {
|
|
7479
|
+
total += block.data.length;
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
return total;
|
|
7483
|
+
}, "inlineMediaBlockBytes");
|
|
6950
7484
|
var DEFAULT_MAX_SESSIONS = 32;
|
|
6951
7485
|
var DEFAULT_MAX_PENDING_PROMPTS_PER_SESSION = 5;
|
|
7486
|
+
var CHAT_RECORD_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
6952
7487
|
var MAX_EVENT_RING_SIZE = 1e6;
|
|
6953
7488
|
var DEFAULT_PERMISSION_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
6954
7489
|
var DEFAULT_MAX_PENDING_PER_SESSION = 64;
|
|
6955
7490
|
var DEFAULT_SESSION_REAP_INTERVAL_MS = 6e4;
|
|
6956
7491
|
var DEFAULT_SESSION_IDLE_TIMEOUT_MS = 30 * 6e4;
|
|
7492
|
+
var MAX_RETAINED_SESSION_MEDIA_BYTES = 512 * 1024 * 1024;
|
|
7493
|
+
var RETAINED_SESSION_MEDIA_TTL_MS = 3 * 60 * 6e4;
|
|
6957
7494
|
function createAcpSessionBridge(opts) {
|
|
6958
7495
|
let liveScreenContextCaptureHandler;
|
|
6959
7496
|
let liveTaskToolRequestHandler;
|
|
@@ -7012,7 +7549,17 @@ function createAcpSessionBridge(opts) {
|
|
|
7012
7549
|
);
|
|
7013
7550
|
}
|
|
7014
7551
|
}, "releaseFreshSessionReservation");
|
|
7552
|
+
const sessionCatalogGeneration = randomUUID3();
|
|
7553
|
+
let sessionCatalogRevision = 0;
|
|
7554
|
+
const getSessionCatalogVersion = /* @__PURE__ */ __name(() => ({
|
|
7555
|
+
generation: sessionCatalogGeneration,
|
|
7556
|
+
revision: sessionCatalogRevision
|
|
7557
|
+
}), "getSessionCatalogVersion");
|
|
7558
|
+
const markSessionCatalogChanged = /* @__PURE__ */ __name(() => {
|
|
7559
|
+
sessionCatalogRevision += 1;
|
|
7560
|
+
}, "markSessionCatalogChanged");
|
|
7015
7561
|
const emitSessionLifecycle = /* @__PURE__ */ __name((event) => {
|
|
7562
|
+
markSessionCatalogChanged();
|
|
7016
7563
|
try {
|
|
7017
7564
|
opts.sessionLifecycle?.(event);
|
|
7018
7565
|
} catch (err) {
|
|
@@ -7082,7 +7629,7 @@ function createAcpSessionBridge(opts) {
|
|
|
7082
7629
|
} else {
|
|
7083
7630
|
maxPendingPromptsPerSession = maxPendingPromptsRaw;
|
|
7084
7631
|
}
|
|
7085
|
-
if (!
|
|
7632
|
+
if (!path4.isAbsolute(opts.boundWorkspace)) {
|
|
7086
7633
|
throw new TypeError(
|
|
7087
7634
|
`Invalid boundWorkspace: "${opts.boundWorkspace}". Must be an absolute path.`
|
|
7088
7635
|
);
|
|
@@ -7105,6 +7652,7 @@ function createAcpSessionBridge(opts) {
|
|
|
7105
7652
|
DEFAULT_SESSION_IDLE_TIMEOUT_MS
|
|
7106
7653
|
);
|
|
7107
7654
|
let sessionReaper;
|
|
7655
|
+
let mediaSweeper;
|
|
7108
7656
|
let lastActivityTimestamp = null;
|
|
7109
7657
|
let activePromptCounter = 0;
|
|
7110
7658
|
function touchActivity() {
|
|
@@ -7158,12 +7706,15 @@ function createAcpSessionBridge(opts) {
|
|
|
7158
7706
|
}
|
|
7159
7707
|
__name(isClosingOrAuthorizingClose, "isClosingOrAuthorizingClose");
|
|
7160
7708
|
async function maybeCloseIdleSession(entry, reason) {
|
|
7161
|
-
if (!
|
|
7162
|
-
|
|
7709
|
+
if (byId.get(entry.sessionId) === entry && !isClosingOrAuthorizingClose(entry) && entry.spawnOwnerWantedKill && entry.attachCount === 0) {
|
|
7710
|
+
writeStderrLine(
|
|
7711
|
+
`qwen serve: completing deferred kill of session ${JSON.stringify(entry.sessionId)} (${reason})`
|
|
7712
|
+
);
|
|
7163
7713
|
await bridgeApi.killSession(entry.sessionId).catch(() => {
|
|
7164
7714
|
});
|
|
7165
7715
|
return;
|
|
7166
7716
|
}
|
|
7717
|
+
if (!entryIsAutoCloseCandidate(entry)) return;
|
|
7167
7718
|
if (entry.clientIds.size > 0) return;
|
|
7168
7719
|
await closeIfChildUnheld(entry, {
|
|
7169
7720
|
trigger: reason,
|
|
@@ -7200,7 +7751,10 @@ function createAcpSessionBridge(opts) {
|
|
|
7200
7751
|
const response = await withTimeout(
|
|
7201
7752
|
entry.connection.extMethod(SERVE_CONTROL_EXT_METHODS.sessionClose, {
|
|
7202
7753
|
sessionId: entry.sessionId,
|
|
7203
|
-
[ACTIVE_WORK_CLOSE_IF_UNHELD_PARAM]: true
|
|
7754
|
+
[ACTIVE_WORK_CLOSE_IF_UNHELD_PARAM]: true,
|
|
7755
|
+
drainTimeoutMs: sessionCloseDrainBudgetMs(
|
|
7756
|
+
ACTIVE_WORK_CLOSE_TIMEOUT_MS
|
|
7757
|
+
)
|
|
7204
7758
|
}),
|
|
7205
7759
|
ACTIVE_WORK_CLOSE_TIMEOUT_MS,
|
|
7206
7760
|
SERVE_CONTROL_EXT_METHODS.sessionClose
|
|
@@ -7415,9 +7969,32 @@ function createAcpSessionBridge(opts) {
|
|
|
7415
7969
|
}
|
|
7416
7970
|
}
|
|
7417
7971
|
__name(withWorkspaceControl, "withWorkspaceControl");
|
|
7972
|
+
function sweepRetainedMedia() {
|
|
7973
|
+
const now = Date.now();
|
|
7974
|
+
for (const [id] of retainedMedia) {
|
|
7975
|
+
if (byId.has(id) || inFlightRestores.has(id)) continue;
|
|
7976
|
+
const detachedAt = retainedMediaDetachedAt.get(id);
|
|
7977
|
+
if (detachedAt === void 0 || now - detachedAt < RETAINED_SESSION_MEDIA_TTL_MS) {
|
|
7978
|
+
continue;
|
|
7979
|
+
}
|
|
7980
|
+
void releaseSessionMedia(id).catch((error) => {
|
|
7981
|
+
writeStderrLine(
|
|
7982
|
+
`qwen serve: failed to release retained media for ${JSON.stringify(id)}: ${error instanceof Error ? error.message : String(error)}`
|
|
7983
|
+
);
|
|
7984
|
+
});
|
|
7985
|
+
}
|
|
7986
|
+
}
|
|
7987
|
+
__name(sweepRetainedMedia, "sweepRetainedMedia");
|
|
7418
7988
|
function startSessionReaper() {
|
|
7419
|
-
if (sessionReapIntervalMs <= 0
|
|
7420
|
-
writeStderrLine(
|
|
7989
|
+
if (sessionReapIntervalMs <= 0) {
|
|
7990
|
+
writeStderrLine(
|
|
7991
|
+
`qwen serve: session reaper disabled; retained media sweep runs every ${DEFAULT_SESSION_REAP_INTERVAL_MS}ms`
|
|
7992
|
+
);
|
|
7993
|
+
mediaSweeper = setInterval(() => {
|
|
7994
|
+
if (shuttingDown) return;
|
|
7995
|
+
sweepRetainedMedia();
|
|
7996
|
+
}, DEFAULT_SESSION_REAP_INTERVAL_MS);
|
|
7997
|
+
mediaSweeper.unref();
|
|
7421
7998
|
return;
|
|
7422
7999
|
}
|
|
7423
8000
|
writeStderrLine(
|
|
@@ -7427,6 +8004,7 @@ function createAcpSessionBridge(opts) {
|
|
|
7427
8004
|
if (shuttingDown) return;
|
|
7428
8005
|
const now = Date.now();
|
|
7429
8006
|
for (const [id, entry] of byId) {
|
|
8007
|
+
if (sessionIdleTimeoutMs <= 0) break;
|
|
7430
8008
|
if (!entryIsAutoCloseCandidate(entry)) continue;
|
|
7431
8009
|
const lastActive = entry.sessionLastSeenAt ?? Date.parse(entry.createdAt);
|
|
7432
8010
|
const idle = now - lastActive;
|
|
@@ -7439,6 +8017,7 @@ function createAcpSessionBridge(opts) {
|
|
|
7439
8017
|
closeReason: "idle_timeout"
|
|
7440
8018
|
});
|
|
7441
8019
|
}
|
|
8020
|
+
sweepRetainedMedia();
|
|
7442
8021
|
}, sessionReapIntervalMs);
|
|
7443
8022
|
sessionReaper.unref();
|
|
7444
8023
|
}
|
|
@@ -7448,11 +8027,29 @@ function createAcpSessionBridge(opts) {
|
|
|
7448
8027
|
clearInterval(sessionReaper);
|
|
7449
8028
|
sessionReaper = void 0;
|
|
7450
8029
|
}
|
|
8030
|
+
if (mediaSweeper !== void 0) {
|
|
8031
|
+
clearInterval(mediaSweeper);
|
|
8032
|
+
mediaSweeper = void 0;
|
|
8033
|
+
}
|
|
7451
8034
|
}
|
|
7452
8035
|
__name(stopSessionReaper, "stopSessionReaper");
|
|
7453
8036
|
const aliveChannels = /* @__PURE__ */ new Set();
|
|
7454
8037
|
let inFlightChannelSpawn;
|
|
7455
8038
|
const byId = /* @__PURE__ */ new Map();
|
|
8039
|
+
const retainedMedia = /* @__PURE__ */ new Map();
|
|
8040
|
+
const retainedMediaDetachedAt = /* @__PURE__ */ new Map();
|
|
8041
|
+
let mediaPutQueue = Promise.resolve();
|
|
8042
|
+
const retainSessionMedia = /* @__PURE__ */ __name((sessionId, store = retainedMedia.get(sessionId) ?? new SessionMediaStore()) => {
|
|
8043
|
+
retainedMedia.set(sessionId, store);
|
|
8044
|
+
return store;
|
|
8045
|
+
}, "retainSessionMedia");
|
|
8046
|
+
const releaseSessionMedia = /* @__PURE__ */ __name(async (sessionId) => {
|
|
8047
|
+
const store = retainedMedia.get(sessionId);
|
|
8048
|
+
if (!store) return;
|
|
8049
|
+
retainedMedia.delete(sessionId);
|
|
8050
|
+
retainedMediaDetachedAt.delete(sessionId);
|
|
8051
|
+
await store.close();
|
|
8052
|
+
}, "releaseSessionMedia");
|
|
7456
8053
|
const forwardRunningPromptCancel = /* @__PURE__ */ __name(async (entry, pending, notification) => {
|
|
7457
8054
|
if (pending.cancelForwardInitial) {
|
|
7458
8055
|
return pending.cancelForwardInitial;
|
|
@@ -7592,7 +8189,7 @@ function createAcpSessionBridge(opts) {
|
|
|
7592
8189
|
return limits;
|
|
7593
8190
|
}, "journalSessionLimits");
|
|
7594
8191
|
const unregisterJournalGrowthSessionLimits = journalGrowthPolicy !== void 0 && opts.registerJournalGrowthSessionLimits !== void 0 ? opts.registerJournalGrowthSessionLimits(journalSessionLimits) : void 0;
|
|
7595
|
-
const createClientId = /* @__PURE__ */ __name(() => `client_${
|
|
8192
|
+
const createClientId = /* @__PURE__ */ __name(() => `client_${randomUUID3()}`, "createClientId");
|
|
7596
8193
|
const registerClient = /* @__PURE__ */ __name((entry, requestedClientId) => {
|
|
7597
8194
|
if (requestedClientId && entry.clientIds.has(requestedClientId)) {
|
|
7598
8195
|
entry.clientIds.set(
|
|
@@ -7651,7 +8248,7 @@ function createAcpSessionBridge(opts) {
|
|
|
7651
8248
|
if (inFlightChannelSpawn) return await inFlightChannelSpawn;
|
|
7652
8249
|
const promise = (async () => {
|
|
7653
8250
|
const privateParentCapability = randomBytes(32).toString("base64url");
|
|
7654
|
-
const acpChannelId =
|
|
8251
|
+
const acpChannelId = randomUUID3();
|
|
7655
8252
|
const channel = await telemetry.withSpan(
|
|
7656
8253
|
"channel.spawn",
|
|
7657
8254
|
{
|
|
@@ -7772,7 +8369,10 @@ function createAcpSessionBridge(opts) {
|
|
|
7772
8369
|
const currentInfo = infoRef.current;
|
|
7773
8370
|
if (!currentInfo) return;
|
|
7774
8371
|
applyActiveWorkSnapshot(currentInfo, snapshot);
|
|
7775
|
-
}
|
|
8372
|
+
},
|
|
8373
|
+
// Child-side automatic title updates change persisted catalog
|
|
8374
|
+
// metadata the bridge never sees; forward the catalog-clock mark.
|
|
8375
|
+
markSessionCatalogChanged
|
|
7776
8376
|
);
|
|
7777
8377
|
const rawConnection = new ClientSideConnection(
|
|
7778
8378
|
() => channel.transportGuard ? createLogSafeAcpClient(client, channel.transportGuard) : client,
|
|
@@ -7910,6 +8510,9 @@ function createAcpSessionBridge(opts) {
|
|
|
7910
8510
|
touchActivity();
|
|
7911
8511
|
}
|
|
7912
8512
|
byId.delete(sid);
|
|
8513
|
+
if (retainedMedia.has(sid)) {
|
|
8514
|
+
retainedMediaDetachedAt.set(sid, Date.now());
|
|
8515
|
+
}
|
|
7913
8516
|
telemetry.metrics?.sessionLifecycle("die");
|
|
7914
8517
|
emitSessionLifecycle({
|
|
7915
8518
|
type: "removed",
|
|
@@ -8730,7 +9333,9 @@ function createAcpSessionBridge(opts) {
|
|
|
8730
9333
|
SERVE_CONTROL_EXT_METHODS.sessionClose,
|
|
8731
9334
|
{
|
|
8732
9335
|
sessionId: entry.sessionId,
|
|
8733
|
-
drainTimeoutMs:
|
|
9336
|
+
drainTimeoutMs: sessionCloseDrainBudgetMs(
|
|
9337
|
+
opts2?.timeoutMs ?? initTimeoutMs
|
|
9338
|
+
),
|
|
8734
9339
|
...opts2?.requireFlush === true ? { requireFlush: true } : {}
|
|
8735
9340
|
}
|
|
8736
9341
|
);
|
|
@@ -8945,6 +9550,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8945
9550
|
workspaceCwd,
|
|
8946
9551
|
persistence: createSessionArtifactPersistence(ci.connection, sessionId)
|
|
8947
9552
|
}),
|
|
9553
|
+
media: retainSessionMedia(sessionId),
|
|
8948
9554
|
recordingDegraded: false,
|
|
8949
9555
|
closing: false,
|
|
8950
9556
|
cwdChangeQueue: Promise.resolve(),
|
|
@@ -8952,6 +9558,9 @@ function createAcpSessionBridge(opts) {
|
|
|
8952
9558
|
pendingPromptCount: 0,
|
|
8953
9559
|
pendingAgentNotificationCount: 0,
|
|
8954
9560
|
pendingPromptList: [],
|
|
9561
|
+
terminalTurnStatuses: /* @__PURE__ */ new Map(),
|
|
9562
|
+
enrichedTerminalPromptIds: /* @__PURE__ */ new Set(),
|
|
9563
|
+
rewindGeneration: 0,
|
|
8955
9564
|
midTurnMessageQueue: [],
|
|
8956
9565
|
settledMidTurnMessageIds: [],
|
|
8957
9566
|
promotedMidTurnMessageIds: [],
|
|
@@ -9531,7 +10140,7 @@ function createAcpSessionBridge(opts) {
|
|
|
9531
10140
|
SERVE_CONTROL_EXT_METHODS.sessionClose,
|
|
9532
10141
|
{
|
|
9533
10142
|
sessionId: req.sessionId,
|
|
9534
|
-
drainTimeoutMs:
|
|
10143
|
+
drainTimeoutMs: sessionCloseDrainBudgetMs(initTimeoutMs)
|
|
9535
10144
|
}
|
|
9536
10145
|
),
|
|
9537
10146
|
initTimeoutMs,
|
|
@@ -9901,6 +10510,9 @@ function createAcpSessionBridge(opts) {
|
|
|
9901
10510
|
const restoreEntry = byId.get(req.sessionId);
|
|
9902
10511
|
if (restoreEntry?.events === restoreEvents) {
|
|
9903
10512
|
byId.delete(req.sessionId);
|
|
10513
|
+
if (retainedMedia.has(req.sessionId)) {
|
|
10514
|
+
retainedMediaDetachedAt.set(req.sessionId, Date.now());
|
|
10515
|
+
}
|
|
9904
10516
|
ci?.sessionIds.delete(req.sessionId);
|
|
9905
10517
|
emitSessionLifecycle({
|
|
9906
10518
|
type: "removed",
|
|
@@ -10064,6 +10676,15 @@ function createAcpSessionBridge(opts) {
|
|
|
10064
10676
|
} catch {
|
|
10065
10677
|
}
|
|
10066
10678
|
entry.events.close();
|
|
10679
|
+
if (reason === "last_client_detached" || reason === "idle_timeout") {
|
|
10680
|
+
retainedMediaDetachedAt.set(sessionId, Date.now());
|
|
10681
|
+
} else {
|
|
10682
|
+
await releaseSessionMedia(sessionId).catch((error) => {
|
|
10683
|
+
writeStderrLine(
|
|
10684
|
+
`qwen serve: failed to release media for closed session ${JSON.stringify(sessionId)}: ${error instanceof Error ? error.message : String(error)}`
|
|
10685
|
+
);
|
|
10686
|
+
});
|
|
10687
|
+
}
|
|
10067
10688
|
if (!agentSessionClosed) {
|
|
10068
10689
|
try {
|
|
10069
10690
|
await telemetry.withSpan(
|
|
@@ -10092,25 +10713,76 @@ function createAcpSessionBridge(opts) {
|
|
|
10092
10713
|
ring.splice(0, ring.length - MID_TURN_RECONCILIATION_RING_SIZE);
|
|
10093
10714
|
}
|
|
10094
10715
|
}, "rememberMidTurnId");
|
|
10095
|
-
const
|
|
10096
|
-
|
|
10716
|
+
const removeQueuedMedia = /* @__PURE__ */ __name((entry, content) => {
|
|
10717
|
+
for (const block of content ?? []) {
|
|
10718
|
+
if (!isSessionMediaReference(block)) continue;
|
|
10719
|
+
void entry.media.remove(block.mediaId).catch((error) => {
|
|
10720
|
+
writeStderrLine(
|
|
10721
|
+
`[session-media] session=${JSON.stringify(entry.sessionId)} failed to remove queued media ${JSON.stringify(block.mediaId)}: ${JSON.stringify(error instanceof Error ? error.message : String(error))}`
|
|
10722
|
+
);
|
|
10723
|
+
});
|
|
10724
|
+
}
|
|
10725
|
+
}, "removeQueuedMedia");
|
|
10726
|
+
const promoteMidTurnMessage = /* @__PURE__ */ __name((entry, messageId, text, originatorClientId, content) => {
|
|
10727
|
+
const resolvableBlocks = [];
|
|
10728
|
+
let degraded = 0;
|
|
10729
|
+
for (const block of content ?? []) {
|
|
10730
|
+
try {
|
|
10731
|
+
entry.media.assertReference(block);
|
|
10732
|
+
resolvableBlocks.push(block);
|
|
10733
|
+
} catch (error) {
|
|
10734
|
+
if (!(error instanceof SessionMediaReferenceError)) throw error;
|
|
10735
|
+
degraded += 1;
|
|
10736
|
+
}
|
|
10737
|
+
}
|
|
10738
|
+
let prompt = [
|
|
10739
|
+
...text ? [{ type: "text", text }] : [],
|
|
10740
|
+
...resolvableBlocks
|
|
10741
|
+
];
|
|
10742
|
+
if (degraded > 0) {
|
|
10743
|
+
prompt = withMediaDegradationMarker(prompt);
|
|
10744
|
+
}
|
|
10745
|
+
const context = {
|
|
10746
|
+
promptId: messageId,
|
|
10747
|
+
promotedMidTurn: { originatorClientId },
|
|
10748
|
+
onPromptAdmitted: /* @__PURE__ */ __name(() => {
|
|
10749
|
+
rememberMidTurnId(entry.promotedMidTurnMessageIds, messageId);
|
|
10750
|
+
}, "onPromptAdmitted")
|
|
10751
|
+
};
|
|
10752
|
+
const sendFallback = /* @__PURE__ */ __name(() => bridgeApi.sendPrompt(
|
|
10097
10753
|
entry.sessionId,
|
|
10098
10754
|
{
|
|
10099
10755
|
sessionId: entry.sessionId,
|
|
10100
|
-
prompt:
|
|
10756
|
+
prompt: withMediaDegradationMarker(
|
|
10757
|
+
text ? [{ type: "text", text }] : []
|
|
10758
|
+
)
|
|
10101
10759
|
},
|
|
10102
10760
|
void 0,
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10761
|
+
context
|
|
10762
|
+
), "sendFallback");
|
|
10763
|
+
let result;
|
|
10764
|
+
try {
|
|
10765
|
+
result = bridgeApi.sendPrompt(
|
|
10766
|
+
entry.sessionId,
|
|
10767
|
+
{
|
|
10768
|
+
sessionId: entry.sessionId,
|
|
10769
|
+
prompt
|
|
10770
|
+
},
|
|
10771
|
+
void 0,
|
|
10772
|
+
context
|
|
10773
|
+
);
|
|
10774
|
+
} catch (error) {
|
|
10775
|
+
try {
|
|
10776
|
+
if (!(error instanceof SessionMediaReferenceError)) throw error;
|
|
10777
|
+
result = sendFallback();
|
|
10778
|
+
} catch (fallbackError) {
|
|
10779
|
+
writeStderrLine(
|
|
10780
|
+
`[mid-turn] session=${JSON.stringify(entry.sessionId)} failed to run promoted message ${JSON.stringify(messageId)}: ${JSON.stringify(fallbackError instanceof Error ? fallbackError.message : String(fallbackError))}`
|
|
10781
|
+
);
|
|
10782
|
+
return;
|
|
10783
|
+
}
|
|
10784
|
+
}
|
|
10785
|
+
void result.catch((error) => {
|
|
10114
10786
|
writeStderrLine(
|
|
10115
10787
|
`[mid-turn] session=${JSON.stringify(entry.sessionId)} failed to run promoted message ${JSON.stringify(messageId)}: ${JSON.stringify(error instanceof Error ? error.message : String(error))}`
|
|
10116
10788
|
);
|
|
@@ -10430,7 +11102,7 @@ function createAcpSessionBridge(opts) {
|
|
|
10430
11102
|
req.branch,
|
|
10431
11103
|
req.sessionId
|
|
10432
11104
|
);
|
|
10433
|
-
const tracker = effectiveScope === "single" ? workspaceKey : `${workspaceKey}#${
|
|
11105
|
+
const tracker = effectiveScope === "single" ? workspaceKey : `${workspaceKey}#${randomUUID3()}`;
|
|
10434
11106
|
inFlightSpawns.set(tracker, promise);
|
|
10435
11107
|
try {
|
|
10436
11108
|
return await promise;
|
|
@@ -10460,9 +11132,15 @@ function createAcpSessionBridge(opts) {
|
|
|
10460
11132
|
)
|
|
10461
11133
|
);
|
|
10462
11134
|
}
|
|
11135
|
+
if (!Array.isArray(req.prompt)) {
|
|
11136
|
+
return Promise.reject(
|
|
11137
|
+
RequestError.invalidParams(void 0, "Prompt must be an array")
|
|
11138
|
+
);
|
|
11139
|
+
}
|
|
10463
11140
|
const promotedMidTurn = context?.promotedMidTurn;
|
|
10464
11141
|
const isPromotedMidTurn = promotedMidTurn !== void 0;
|
|
10465
11142
|
const originatorClientId = promotedMidTurn ? promotedMidTurn.originatorClientId : resolveTrustedClientId(entry, context?.clientId);
|
|
11143
|
+
entry.media.assertReferences(req.prompt);
|
|
10466
11144
|
const modelPrompt = context?.modelPrompt;
|
|
10467
11145
|
if (modelPrompt !== void 0 && !isValidTrustedModelPrompt(modelPrompt)) {
|
|
10468
11146
|
throw new TypeError(
|
|
@@ -10486,7 +11164,7 @@ function createAcpSessionBridge(opts) {
|
|
|
10486
11164
|
promptSlotReleased = true;
|
|
10487
11165
|
entry.pendingPromptCount = Math.max(0, entry.pendingPromptCount - 1);
|
|
10488
11166
|
}, "releasePromptSlot");
|
|
10489
|
-
const promptId = context?.promptId ??
|
|
11167
|
+
const promptId = context?.promptId ?? randomUUID3();
|
|
10490
11168
|
const invocationContext = Object.freeze({
|
|
10491
11169
|
version: 1,
|
|
10492
11170
|
sessionId,
|
|
@@ -10519,6 +11197,7 @@ function createAcpSessionBridge(opts) {
|
|
|
10519
11197
|
...originatorClientId !== void 0 ? { originatorClientId } : {},
|
|
10520
11198
|
...isPromotedMidTurn ? { promotedMidTurn: true } : {},
|
|
10521
11199
|
text: pendingText,
|
|
11200
|
+
content: extractMediaBlocks(req.prompt),
|
|
10522
11201
|
abortController: pendingAbort,
|
|
10523
11202
|
state: isQueued ? "queued" : "running"
|
|
10524
11203
|
};
|
|
@@ -10611,6 +11290,7 @@ function createAcpSessionBridge(opts) {
|
|
|
10611
11290
|
}
|
|
10612
11291
|
throw new DOMException("Prompt aborted", "AbortError");
|
|
10613
11292
|
}
|
|
11293
|
+
pendingEntry.startedAt = Date.now();
|
|
10614
11294
|
if (pendingEntry.state === "queued" || isPromotedMidTurn) {
|
|
10615
11295
|
if (pendingEntry.state === "queued") {
|
|
10616
11296
|
delete entry.todoStopGuardAwaitingQueuedPromptOwnerPromptId;
|
|
@@ -10638,10 +11318,25 @@ function createAcpSessionBridge(opts) {
|
|
|
10638
11318
|
...context?.clientId ? { "qwen-code.client_id": context.clientId } : {}
|
|
10639
11319
|
},
|
|
10640
11320
|
async () => {
|
|
11321
|
+
let dispatchBlocks = req.prompt;
|
|
11322
|
+
let resolvedPrompt;
|
|
11323
|
+
try {
|
|
11324
|
+
resolvedPrompt = await entry.media.resolveContent(dispatchBlocks);
|
|
11325
|
+
} catch (error) {
|
|
11326
|
+
if (!isPromotedMidTurn || !(error instanceof SessionMediaReferenceError)) {
|
|
11327
|
+
throw error;
|
|
11328
|
+
}
|
|
11329
|
+
const perBlock = await entry.media.resolveContentDegrading(dispatchBlocks);
|
|
11330
|
+
dispatchBlocks = perBlock.retainedBlocks;
|
|
11331
|
+
resolvedPrompt = withMediaDegradationMarker(
|
|
11332
|
+
perBlock.resolvedBlocks
|
|
11333
|
+
);
|
|
11334
|
+
}
|
|
10641
11335
|
const normalized = telemetry.injectPromptContext(
|
|
10642
11336
|
{
|
|
10643
11337
|
...req,
|
|
10644
|
-
sessionId
|
|
11338
|
+
sessionId,
|
|
11339
|
+
prompt: resolvedPrompt
|
|
10645
11340
|
}
|
|
10646
11341
|
);
|
|
10647
11342
|
assertLivePromptEntry(sessionId, entry);
|
|
@@ -10664,6 +11359,7 @@ function createAcpSessionBridge(opts) {
|
|
|
10664
11359
|
delete meta[DAEMON_CHANNEL_DELIVERY_META_KEY];
|
|
10665
11360
|
delete meta[DAEMON_PROMPT_DISPLAY_TEXT_META_KEY];
|
|
10666
11361
|
delete meta[DAEMON_MODEL_PROMPT_META_KEY];
|
|
11362
|
+
delete meta[DAEMON_MEDIA_REFERENCES_META_KEY];
|
|
10667
11363
|
delete meta[CHANNEL_PROMPT_META_KEY];
|
|
10668
11364
|
if (isRetry) {
|
|
10669
11365
|
meta[DAEMON_RETRY_META_KEY] = true;
|
|
@@ -10680,6 +11376,12 @@ function createAcpSessionBridge(opts) {
|
|
|
10680
11376
|
if (modelPrompt !== void 0) {
|
|
10681
11377
|
meta[DAEMON_MODEL_PROMPT_META_KEY] = modelPrompt;
|
|
10682
11378
|
}
|
|
11379
|
+
const mediaReferences = dispatchBlocks.filter(
|
|
11380
|
+
isSessionMediaReference
|
|
11381
|
+
);
|
|
11382
|
+
if (mediaReferences.length > 0) {
|
|
11383
|
+
meta[DAEMON_MEDIA_REFERENCES_META_KEY] = mediaReferences;
|
|
11384
|
+
}
|
|
10683
11385
|
if (context?.channelPrompt === true) {
|
|
10684
11386
|
meta[CHANNEL_PROMPT_META_KEY] = true;
|
|
10685
11387
|
}
|
|
@@ -10708,7 +11410,10 @@ function createAcpSessionBridge(opts) {
|
|
|
10708
11410
|
if (!isRetry && !isContinue) {
|
|
10709
11411
|
echoPromptToSessionBus(
|
|
10710
11412
|
entry,
|
|
10711
|
-
|
|
11413
|
+
{
|
|
11414
|
+
...promptRequest,
|
|
11415
|
+
prompt: dispatchBlocks
|
|
11416
|
+
},
|
|
10712
11417
|
pendingEntry.promptId,
|
|
10713
11418
|
originatorClientId,
|
|
10714
11419
|
channelDisplayText
|
|
@@ -10864,7 +11569,8 @@ function createAcpSessionBridge(opts) {
|
|
|
10864
11569
|
entry,
|
|
10865
11570
|
message.messageId,
|
|
10866
11571
|
message.text,
|
|
10867
|
-
message.originatorClientId
|
|
11572
|
+
message.originatorClientId,
|
|
11573
|
+
message.content
|
|
10868
11574
|
);
|
|
10869
11575
|
}
|
|
10870
11576
|
void maybeCloseIdleSession(entry, "prompt_settled");
|
|
@@ -11044,60 +11750,87 @@ function createAcpSessionBridge(opts) {
|
|
|
11044
11750
|
if (shuttingDown) throw new Error("AcpSessionBridge is shutting down");
|
|
11045
11751
|
const entry = byId.get(sessionId);
|
|
11046
11752
|
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
11753
|
+
if (isClosingOrAuthorizingClose(entry)) {
|
|
11754
|
+
throw new SessionNotFoundError(sessionId, "The session is closing");
|
|
11755
|
+
}
|
|
11047
11756
|
const source = parseSessionSource(req.sourceType, req.sourceId);
|
|
11048
11757
|
if ("error" in source) {
|
|
11049
11758
|
throw new InvalidSessionMetadataError("sourceType", source.error);
|
|
11050
11759
|
}
|
|
11051
11760
|
const isSideTask = source.sourceType === "side_task";
|
|
11052
|
-
|
|
11761
|
+
const restoreBranch = isSideTask || req.atRecordId === void 0;
|
|
11053
11762
|
if (context?.clientId !== void 0) {
|
|
11054
|
-
|
|
11763
|
+
resolveTrustedClientId(entry, context.clientId);
|
|
11055
11764
|
}
|
|
11056
11765
|
const concurrentSideTask = isSideTask && entry.promptActive;
|
|
11766
|
+
if (!isSideTask && (entry.pendingPromptCount > 0 || entry.promptActive)) {
|
|
11767
|
+
throw new BranchWhilePromptActiveError(sessionId);
|
|
11768
|
+
}
|
|
11057
11769
|
const branchResult = (concurrentSideTask ? Promise.resolve() : entry.promptQueue).then(async () => {
|
|
11058
|
-
if (entry.
|
|
11059
|
-
throw new
|
|
11770
|
+
if (isClosingOrAuthorizingClose(entry) || byId.get(sessionId) !== entry) {
|
|
11771
|
+
throw new SessionNotFoundError(sessionId, "The session is closing");
|
|
11060
11772
|
}
|
|
11061
11773
|
assertFreshSessionsAvailable();
|
|
11062
|
-
|
|
11063
|
-
|
|
11774
|
+
let admission;
|
|
11775
|
+
if (restoreBranch) {
|
|
11776
|
+
if (byId.size + inFlightSpawns.size + inFlightRestores.size >= maxSessions) {
|
|
11777
|
+
throw new SessionLimitExceededError(maxSessions);
|
|
11778
|
+
}
|
|
11779
|
+
admission = reserveFreshSession({
|
|
11780
|
+
operation: "branch",
|
|
11781
|
+
workspaceCwd: boundWorkspace,
|
|
11782
|
+
sourceSessionId: sessionId
|
|
11783
|
+
});
|
|
11064
11784
|
}
|
|
11065
|
-
const admission = reserveFreshSession({
|
|
11066
|
-
operation: "branch",
|
|
11067
|
-
workspaceCwd: boundWorkspace,
|
|
11068
|
-
sourceSessionId: sessionId
|
|
11069
|
-
});
|
|
11070
11785
|
let admissionReleased = false;
|
|
11071
11786
|
const releaseAdmissionOnce = /* @__PURE__ */ __name(() => {
|
|
11072
|
-
if (admissionReleased) return;
|
|
11787
|
+
if (admissionReleased || !admission) return;
|
|
11073
11788
|
admissionReleased = true;
|
|
11074
11789
|
releaseFreshSessionReservation(admission);
|
|
11075
11790
|
}, "releaseAdmissionOnce");
|
|
11076
11791
|
try {
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
cwd: boundWorkspace,
|
|
11086
|
-
name: req.name
|
|
11087
|
-
}
|
|
11088
|
-
),
|
|
11089
|
-
getTransportClosedReject(entry)
|
|
11090
|
-
]),
|
|
11091
|
-
initTimeoutMs,
|
|
11092
|
-
isSideTask ? "createSideTaskSession" : "branchSession"
|
|
11792
|
+
const mutation = entry.connection.extMethod(
|
|
11793
|
+
isSideTask ? SERVE_CONTROL_EXT_METHODS.sessionSideTask : SERVE_CONTROL_EXT_METHODS.sessionBranch,
|
|
11794
|
+
{
|
|
11795
|
+
sessionId,
|
|
11796
|
+
cwd: boundWorkspace,
|
|
11797
|
+
name: req.name,
|
|
11798
|
+
...req.atRecordId !== void 0 ? { atRecordId: req.atRecordId } : {}
|
|
11799
|
+
}
|
|
11093
11800
|
);
|
|
11801
|
+
let result;
|
|
11802
|
+
try {
|
|
11803
|
+
result = await Promise.race([
|
|
11804
|
+
mutation,
|
|
11805
|
+
getTransportClosedReject(entry)
|
|
11806
|
+
]);
|
|
11807
|
+
} catch (err) {
|
|
11808
|
+
const data = err?.data;
|
|
11809
|
+
if (!isSideTask && data && typeof data === "object" && data.errorKind === "session_busy") {
|
|
11810
|
+
const msg = err?.message ?? "Branch failed";
|
|
11811
|
+
throw new SessionBusyError(sessionId, msg);
|
|
11812
|
+
}
|
|
11813
|
+
throw err;
|
|
11814
|
+
}
|
|
11094
11815
|
if (!result || typeof result.newSessionId !== "string") {
|
|
11095
11816
|
throw new Error(
|
|
11096
11817
|
`branchSession: agent returned invalid response: ${JSON.stringify(result)}`
|
|
11097
11818
|
);
|
|
11098
11819
|
}
|
|
11820
|
+
markSessionCatalogChanged();
|
|
11099
11821
|
const rawBranchName = result.displayName ?? result.title;
|
|
11100
11822
|
const branchDisplayName = typeof rawBranchName === "string" ? rawBranchName : result.newSessionId.slice(0, 8);
|
|
11823
|
+
if (!restoreBranch) {
|
|
11824
|
+
return {
|
|
11825
|
+
sessionId: result.newSessionId,
|
|
11826
|
+
displayName: branchDisplayName,
|
|
11827
|
+
forkedFrom: {
|
|
11828
|
+
sessionId,
|
|
11829
|
+
displayName: entry.displayName ?? sessionId.slice(0, 8)
|
|
11830
|
+
}
|
|
11831
|
+
};
|
|
11832
|
+
}
|
|
11833
|
+
const ci = await ensureChannel();
|
|
11101
11834
|
let restored;
|
|
11102
11835
|
try {
|
|
11103
11836
|
const hideInheritedHistory = req.replayInheritedHistory === false;
|
|
@@ -11120,7 +11853,7 @@ function createAcpSessionBridge(opts) {
|
|
|
11120
11853
|
releaseAdmissionOnce();
|
|
11121
11854
|
} catch (restoreErr) {
|
|
11122
11855
|
writeStderrLine(
|
|
11123
|
-
`qwen serve: branchSession load failed for ${result.newSessionId}
|
|
11856
|
+
`qwen serve: branchSession load failed for ${result.newSessionId}; closing partial live state while preserving the committed session...`
|
|
11124
11857
|
);
|
|
11125
11858
|
try {
|
|
11126
11859
|
if (!ci.isDying) {
|
|
@@ -11130,7 +11863,8 @@ function createAcpSessionBridge(opts) {
|
|
|
11130
11863
|
SERVE_CONTROL_EXT_METHODS.sessionClose,
|
|
11131
11864
|
{
|
|
11132
11865
|
sessionId: result.newSessionId,
|
|
11133
|
-
cwd: boundWorkspace
|
|
11866
|
+
cwd: boundWorkspace,
|
|
11867
|
+
drainTimeoutMs: sessionCloseDrainBudgetMs(initTimeoutMs)
|
|
11134
11868
|
}
|
|
11135
11869
|
),
|
|
11136
11870
|
channelUnavailableReject(
|
|
@@ -11144,7 +11878,7 @@ function createAcpSessionBridge(opts) {
|
|
|
11144
11878
|
}
|
|
11145
11879
|
} catch (cleanupErr) {
|
|
11146
11880
|
writeStderrLine(
|
|
11147
|
-
`qwen serve: branchSession
|
|
11881
|
+
`qwen serve: branchSession live-state close for ${result.newSessionId} failed: ${cleanupErr instanceof Error ? cleanupErr.message : cleanupErr}`
|
|
11148
11882
|
);
|
|
11149
11883
|
}
|
|
11150
11884
|
throw restoreErr;
|
|
@@ -11174,19 +11908,6 @@ function createAcpSessionBridge(opts) {
|
|
|
11174
11908
|
);
|
|
11175
11909
|
}
|
|
11176
11910
|
}
|
|
11177
|
-
if (!isSideTask) {
|
|
11178
|
-
const eventData = {
|
|
11179
|
-
sourceSessionId: sessionId,
|
|
11180
|
-
newSessionId: result.newSessionId,
|
|
11181
|
-
displayName: branchDisplayName
|
|
11182
|
-
};
|
|
11183
|
-
const branchEnvelope = {
|
|
11184
|
-
type: "session_branched",
|
|
11185
|
-
data: eventData,
|
|
11186
|
-
...originatorClientId ? { originatorClientId } : {}
|
|
11187
|
-
};
|
|
11188
|
-
newEntry?.events.publish(branchEnvelope);
|
|
11189
|
-
}
|
|
11190
11911
|
return {
|
|
11191
11912
|
...restored,
|
|
11192
11913
|
displayName: branchDisplayName,
|
|
@@ -11219,7 +11940,8 @@ function createAcpSessionBridge(opts) {
|
|
|
11219
11940
|
},
|
|
11220
11941
|
context
|
|
11221
11942
|
);
|
|
11222
|
-
const
|
|
11943
|
+
const restoredResult = result;
|
|
11944
|
+
const { forkedFrom: _forkedFrom, ...sideTask } = restoredResult;
|
|
11223
11945
|
return {
|
|
11224
11946
|
...sideTask,
|
|
11225
11947
|
parentSessionId: sessionId
|
|
@@ -11289,6 +12011,7 @@ function createAcpSessionBridge(opts) {
|
|
|
11289
12011
|
const entry = byId.get(sessionId);
|
|
11290
12012
|
if (entry) {
|
|
11291
12013
|
entry.worktree = worktree;
|
|
12014
|
+
markSessionCatalogChanged();
|
|
11292
12015
|
}
|
|
11293
12016
|
},
|
|
11294
12017
|
async closeSession(sessionId, context, closeOpts) {
|
|
@@ -11314,6 +12037,7 @@ function createAcpSessionBridge(opts) {
|
|
|
11314
12037
|
const nextDisplayName = metadata.displayName || void 0;
|
|
11315
12038
|
if (entry.displayName !== nextDisplayName) {
|
|
11316
12039
|
entry.displayName = nextDisplayName;
|
|
12040
|
+
markSessionCatalogChanged();
|
|
11317
12041
|
writeStderrLine(
|
|
11318
12042
|
`qwen serve: updated session metadata ${JSON.stringify(sessionId)} displayName=${entry.displayName === void 0 ? "cleared" : "set"}` + (context?.clientId ? ` by client ${JSON.stringify(context.clientId)}` : "")
|
|
11319
12043
|
);
|
|
@@ -11376,7 +12100,7 @@ function createAcpSessionBridge(opts) {
|
|
|
11376
12100
|
return warnings.length > 0 ? { ...result, warnings } : result;
|
|
11377
12101
|
},
|
|
11378
12102
|
listWorkspaceSessions(workspaceCwd) {
|
|
11379
|
-
if (!
|
|
12103
|
+
if (!path4.isAbsolute(workspaceCwd)) return [];
|
|
11380
12104
|
const key = workspaceCwd === boundWorkspace ? boundWorkspace : canonicalizeWorkspace(workspaceCwd);
|
|
11381
12105
|
if (key !== boundWorkspace) return [];
|
|
11382
12106
|
const out = [];
|
|
@@ -11387,6 +12111,8 @@ function createAcpSessionBridge(opts) {
|
|
|
11387
12111
|
}
|
|
11388
12112
|
return out;
|
|
11389
12113
|
},
|
|
12114
|
+
getSessionCatalogVersion,
|
|
12115
|
+
markSessionCatalogChanged,
|
|
11390
12116
|
getSessionSummary(sessionId) {
|
|
11391
12117
|
const entry = byId.get(sessionId);
|
|
11392
12118
|
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
@@ -12079,7 +12805,7 @@ function createAcpSessionBridge(opts) {
|
|
|
12079
12805
|
const info = channelInfoForEntry(entry);
|
|
12080
12806
|
if (!info || info.isDying) throw new SessionNotFoundError(sessionId);
|
|
12081
12807
|
resolveTrustedClientId(entry, context?.clientId);
|
|
12082
|
-
const requestId =
|
|
12808
|
+
const requestId = randomUUID3();
|
|
12083
12809
|
const queue = new GenerationStreamQueue(
|
|
12084
12810
|
GENERATION_STREAM_QUEUE_CAPACITY
|
|
12085
12811
|
);
|
|
@@ -12146,14 +12872,110 @@ function createAcpSessionBridge(opts) {
|
|
|
12146
12872
|
const entry = byId.get(sessionId);
|
|
12147
12873
|
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
12148
12874
|
resolveTrustedClientId(entry, context?.clientId);
|
|
12149
|
-
return entry.pendingPromptList.filter((p) => !p.removed).map((p) => ({
|
|
12875
|
+
return entry.pendingPromptList.filter((p) => !p.removed && !p.terminalPublished).map((p) => ({
|
|
12150
12876
|
promptId: p.promptId,
|
|
12151
12877
|
text: p.text,
|
|
12878
|
+
...p.content ? { content: p.content } : {},
|
|
12152
12879
|
queuedAt: p.queuedAt,
|
|
12153
12880
|
state: p.state,
|
|
12154
12881
|
...p.originatorClientId !== void 0 ? { originatorClientId: p.originatorClientId } : {}
|
|
12155
12882
|
}));
|
|
12156
12883
|
},
|
|
12884
|
+
async getSessionTurnStatus(sessionId, context, promptId) {
|
|
12885
|
+
const entry = byId.get(sessionId);
|
|
12886
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
12887
|
+
resolveTrustedClientId(entry, context?.clientId);
|
|
12888
|
+
const liveBeforeRead = findLiveTurnStatus(entry, promptId);
|
|
12889
|
+
if (liveBeforeRead) return liveBeforeRead;
|
|
12890
|
+
if (promptId !== void 0 && entry.enrichedTerminalPromptIds.has(promptId)) {
|
|
12891
|
+
const enrichedTerminal = entry.terminalTurnStatuses.get(promptId);
|
|
12892
|
+
if (enrichedTerminal) return enrichedTerminal;
|
|
12893
|
+
}
|
|
12894
|
+
const rewindGenerationBeforeRead = entry.rewindGeneration;
|
|
12895
|
+
let result;
|
|
12896
|
+
try {
|
|
12897
|
+
result = await requestSessionStatus(
|
|
12898
|
+
sessionId,
|
|
12899
|
+
SERVE_CONTROL_EXT_METHODS.sessionTurnStatus,
|
|
12900
|
+
{ ...promptId !== void 0 ? { promptId } : {} },
|
|
12901
|
+
// Transcript scans of large histories exceed the 10s init default;
|
|
12902
|
+
// give the read the same budget as other transcript reads.
|
|
12903
|
+
SESSION_TRANSCRIPT_TIMEOUT_MS
|
|
12904
|
+
);
|
|
12905
|
+
} catch (error) {
|
|
12906
|
+
const liveAfterFailure = findLiveTurnStatus(entry, promptId);
|
|
12907
|
+
if (liveAfterFailure) return liveAfterFailure;
|
|
12908
|
+
const terminalAfterFailure = promptId !== void 0 ? entry.terminalTurnStatuses.get(promptId) : latestTerminalTurnStatus(entry);
|
|
12909
|
+
if (terminalAfterFailure) return terminalAfterFailure;
|
|
12910
|
+
throw error;
|
|
12911
|
+
}
|
|
12912
|
+
const liveAfterRead = findLiveTurnStatus(entry, promptId);
|
|
12913
|
+
if (liveAfterRead) return liveAfterRead;
|
|
12914
|
+
const terminal = promptId !== void 0 ? entry.terminalTurnStatuses.get(promptId) : latestTerminalTurnStatus(entry);
|
|
12915
|
+
const persisted = result.turnResult && entry.rewindGeneration === rewindGenerationBeforeRead ? settledTurnStatus(sessionId, result.turnResult) : void 0;
|
|
12916
|
+
if (promptId !== void 0) {
|
|
12917
|
+
if (terminal && persisted) {
|
|
12918
|
+
const merged = mergeTerminalWithPersisted(terminal, persisted);
|
|
12919
|
+
rememberEnrichedTerminalTurnStatus(entry, promptId, merged);
|
|
12920
|
+
return merged;
|
|
12921
|
+
}
|
|
12922
|
+
if (terminal) return terminal;
|
|
12923
|
+
if (persisted) {
|
|
12924
|
+
rememberEnrichedTerminalTurnStatus(entry, promptId, persisted);
|
|
12925
|
+
return persisted;
|
|
12926
|
+
}
|
|
12927
|
+
} else {
|
|
12928
|
+
if (terminal && persisted && terminal.promptId === persisted.promptId) {
|
|
12929
|
+
return mergeTerminalWithPersisted(terminal, persisted);
|
|
12930
|
+
}
|
|
12931
|
+
if (terminal && persisted) {
|
|
12932
|
+
return (terminal.endedAt ?? 0) >= (persisted.endedAt ?? 0) ? terminal : persisted;
|
|
12933
|
+
}
|
|
12934
|
+
if (terminal) return terminal;
|
|
12935
|
+
if (persisted) return persisted;
|
|
12936
|
+
}
|
|
12937
|
+
if (promptId !== void 0) {
|
|
12938
|
+
return void 0;
|
|
12939
|
+
}
|
|
12940
|
+
return { sessionId, state: "idle" };
|
|
12941
|
+
},
|
|
12942
|
+
async storeSessionMedia(sessionId, data, mimeType, context) {
|
|
12943
|
+
const entry = byId.get(sessionId);
|
|
12944
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
12945
|
+
resolveTrustedClientId(entry, context?.clientId);
|
|
12946
|
+
const operation = mediaPutQueue.then(async () => {
|
|
12947
|
+
if (byId.get(sessionId) !== entry) {
|
|
12948
|
+
throw new SessionNotFoundError(sessionId);
|
|
12949
|
+
}
|
|
12950
|
+
const retainedBytes = [...new Set(retainedMedia.values())].reduce(
|
|
12951
|
+
(total, store) => total + store.sizeBytes,
|
|
12952
|
+
0
|
|
12953
|
+
);
|
|
12954
|
+
if (retainedBytes + data.byteLength > MAX_RETAINED_SESSION_MEDIA_BYTES) {
|
|
12955
|
+
throw new RangeError(
|
|
12956
|
+
`Session media exceeds the ${MAX_RETAINED_SESSION_MEDIA_BYTES}-byte daemon limit`
|
|
12957
|
+
);
|
|
12958
|
+
}
|
|
12959
|
+
return await entry.media.put(data, mimeType);
|
|
12960
|
+
});
|
|
12961
|
+
mediaPutQueue = operation.then(
|
|
12962
|
+
() => void 0,
|
|
12963
|
+
() => void 0
|
|
12964
|
+
);
|
|
12965
|
+
return await operation;
|
|
12966
|
+
},
|
|
12967
|
+
async readSessionMedia(sessionId, mediaId, context) {
|
|
12968
|
+
const entry = byId.get(sessionId);
|
|
12969
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
12970
|
+
resolveTrustedClientId(entry, context?.clientId);
|
|
12971
|
+
return await entry.media.read(mediaId);
|
|
12972
|
+
},
|
|
12973
|
+
async removeSessionMedia(sessionId, mediaId, context) {
|
|
12974
|
+
const entry = byId.get(sessionId);
|
|
12975
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
12976
|
+
resolveTrustedClientId(entry, context?.clientId);
|
|
12977
|
+
return await entry.media.remove(mediaId);
|
|
12978
|
+
},
|
|
12157
12979
|
removePendingPrompt(sessionId, promptId, context) {
|
|
12158
12980
|
const entry = byId.get(sessionId);
|
|
12159
12981
|
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
@@ -12172,6 +12994,7 @@ function createAcpSessionBridge(opts) {
|
|
|
12172
12994
|
);
|
|
12173
12995
|
if (target.state === "queued") {
|
|
12174
12996
|
entry.pendingPromptList.splice(idx, 1);
|
|
12997
|
+
removeQueuedMedia(entry, target.content);
|
|
12175
12998
|
} else {
|
|
12176
12999
|
target.removed = true;
|
|
12177
13000
|
}
|
|
@@ -12197,7 +13020,10 @@ function createAcpSessionBridge(opts) {
|
|
|
12197
13020
|
context?.clientId
|
|
12198
13021
|
);
|
|
12199
13022
|
const trimmed = message.trim();
|
|
12200
|
-
|
|
13023
|
+
const mediaBlocks = (options?.content ?? []).filter(
|
|
13024
|
+
(block) => block.type === "image"
|
|
13025
|
+
);
|
|
13026
|
+
if (trimmed.length === 0 && mediaBlocks.length === 0) {
|
|
12201
13027
|
writeStderrLine(
|
|
12202
13028
|
`[mid-turn] session=${entry.sessionId} rejected: empty`
|
|
12203
13029
|
);
|
|
@@ -12208,11 +13034,12 @@ function createAcpSessionBridge(opts) {
|
|
|
12208
13034
|
(queued) => queued.messageId === requestedMessageId
|
|
12209
13035
|
);
|
|
12210
13036
|
if (existing) {
|
|
12211
|
-
|
|
13037
|
+
const sameMedia = JSON.stringify(existing.content ?? []) === JSON.stringify(mediaBlocks);
|
|
13038
|
+
if (existing.text === trimmed && sameMedia) {
|
|
12212
13039
|
return { accepted: true, messageId: requestedMessageId };
|
|
12213
13040
|
}
|
|
12214
13041
|
writeStderrLine(
|
|
12215
|
-
`[mid-turn] session=${JSON.stringify(entry.sessionId)} rejected id ${JSON.stringify(requestedMessageId)}: text mismatch`
|
|
13042
|
+
`[mid-turn] session=${JSON.stringify(entry.sessionId)} rejected id ${JSON.stringify(requestedMessageId)}: text or content mismatch`
|
|
12216
13043
|
);
|
|
12217
13044
|
return { accepted: false };
|
|
12218
13045
|
}
|
|
@@ -12220,11 +13047,16 @@ function createAcpSessionBridge(opts) {
|
|
|
12220
13047
|
(pending) => pending.promptId === requestedMessageId
|
|
12221
13048
|
);
|
|
12222
13049
|
if (promoted) {
|
|
12223
|
-
|
|
13050
|
+
const promotedImages = (promoted.content ?? []).filter(
|
|
13051
|
+
(block) => block.type === "image"
|
|
13052
|
+
);
|
|
13053
|
+
const sameMedia = JSON.stringify(promotedImages) === JSON.stringify(mediaBlocks);
|
|
13054
|
+
const promotedText = promoted.text === "[image]" && trimmed.length === 0 ? "" : promoted.text;
|
|
13055
|
+
if (promotedText === trimmed && sameMedia) {
|
|
12224
13056
|
return { accepted: true, messageId: requestedMessageId };
|
|
12225
13057
|
}
|
|
12226
13058
|
writeStderrLine(
|
|
12227
|
-
`[mid-turn] session=${JSON.stringify(entry.sessionId)} rejected promoted id ${JSON.stringify(requestedMessageId)}: text mismatch`
|
|
13059
|
+
`[mid-turn] session=${JSON.stringify(entry.sessionId)} rejected promoted id ${JSON.stringify(requestedMessageId)}: text or content mismatch`
|
|
12228
13060
|
);
|
|
12229
13061
|
return { accepted: false };
|
|
12230
13062
|
}
|
|
@@ -12241,7 +13073,21 @@ function createAcpSessionBridge(opts) {
|
|
|
12241
13073
|
);
|
|
12242
13074
|
return { accepted: false };
|
|
12243
13075
|
}
|
|
12244
|
-
|
|
13076
|
+
entry.media.assertReferences(mediaBlocks);
|
|
13077
|
+
const inlineBytes = inlineMediaBlockBytes(mediaBlocks);
|
|
13078
|
+
if (inlineBytes > 0) {
|
|
13079
|
+
const queuedInlineBytes = entry.midTurnMessageQueue.reduce(
|
|
13080
|
+
(total, queued) => total + inlineMediaBlockBytes(queued.content ?? []),
|
|
13081
|
+
0
|
|
13082
|
+
);
|
|
13083
|
+
if (queuedInlineBytes + inlineBytes > SESSION_MEDIA_MAX_TOTAL_BYTES) {
|
|
13084
|
+
writeStderrLine(
|
|
13085
|
+
`[mid-turn] session=${entry.sessionId} rejected: queued inline media exceeds the ${SESSION_MEDIA_MAX_TOTAL_BYTES}-byte session budget`
|
|
13086
|
+
);
|
|
13087
|
+
return { accepted: false };
|
|
13088
|
+
}
|
|
13089
|
+
}
|
|
13090
|
+
const messageId = requestedMessageId ?? randomUUID3();
|
|
12245
13091
|
if (entry.pendingPromptCount === 0) {
|
|
12246
13092
|
if (options?.queueOnly) {
|
|
12247
13093
|
writeStderrLine(
|
|
@@ -12249,7 +13095,13 @@ function createAcpSessionBridge(opts) {
|
|
|
12249
13095
|
);
|
|
12250
13096
|
return { accepted: false };
|
|
12251
13097
|
}
|
|
12252
|
-
promoteMidTurnMessage(
|
|
13098
|
+
promoteMidTurnMessage(
|
|
13099
|
+
entry,
|
|
13100
|
+
messageId,
|
|
13101
|
+
trimmed,
|
|
13102
|
+
originatorClientId,
|
|
13103
|
+
mediaBlocks.length > 0 ? mediaBlocks : void 0
|
|
13104
|
+
);
|
|
12253
13105
|
return { accepted: true, messageId };
|
|
12254
13106
|
}
|
|
12255
13107
|
if (entry.midTurnMessageQueue.length >= MAX_MID_TURN_QUEUE_DEPTH) {
|
|
@@ -12261,6 +13113,7 @@ function createAcpSessionBridge(opts) {
|
|
|
12261
13113
|
const queuedMessage = {
|
|
12262
13114
|
messageId,
|
|
12263
13115
|
text: trimmed,
|
|
13116
|
+
...mediaBlocks.length > 0 ? { content: mediaBlocks } : {},
|
|
12264
13117
|
originatorClientId,
|
|
12265
13118
|
...options?.queueOnly ? {
|
|
12266
13119
|
queueOnly: true,
|
|
@@ -12320,6 +13173,7 @@ function createAcpSessionBridge(opts) {
|
|
|
12320
13173
|
const [removed] = entry.midTurnMessageQueue.splice(index, 1);
|
|
12321
13174
|
rememberMidTurnId(entry.settledMidTurnMessageIds, messageId);
|
|
12322
13175
|
if (removed) {
|
|
13176
|
+
removeQueuedMedia(entry, removed.content);
|
|
12323
13177
|
try {
|
|
12324
13178
|
entry.events.publish({
|
|
12325
13179
|
type: "pending_prompt_completed",
|
|
@@ -12369,7 +13223,11 @@ function createAcpSessionBridge(opts) {
|
|
|
12369
13223
|
// should restore into their queue views.
|
|
12370
13224
|
messages: entry.midTurnMessageQueue.filter((message) => message.originatorClientId !== void 0).map((message) => ({
|
|
12371
13225
|
messageId: message.messageId,
|
|
12372
|
-
text: message.text
|
|
13226
|
+
text: message.text,
|
|
13227
|
+
// Carry the media blocks so a refreshed client can rebuild the
|
|
13228
|
+
// queued row with its attachments (the snapshot is the only
|
|
13229
|
+
// recovery source once the client's in-memory copy is gone).
|
|
13230
|
+
...message.content ? { content: message.content } : {}
|
|
12373
13231
|
})),
|
|
12374
13232
|
settledMessageIds: [...entry.settledMidTurnMessageIds],
|
|
12375
13233
|
promotedMessageIds: [...entry.promotedMidTurnMessageIds]
|
|
@@ -12634,10 +13492,19 @@ function createAcpSessionBridge(opts) {
|
|
|
12634
13492
|
entry,
|
|
12635
13493
|
context?.clientId
|
|
12636
13494
|
);
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
|
|
13495
|
+
if (entry.pendingPromptCount > 0 || entry.promptActive) {
|
|
13496
|
+
throw new SessionBusyError(
|
|
13497
|
+
sessionId,
|
|
13498
|
+
"Cannot rewind while a prompt is running"
|
|
13499
|
+
);
|
|
13500
|
+
}
|
|
13501
|
+
const rewindResult = entry.promptQueue.then(async () => {
|
|
13502
|
+
if (entry.closing) {
|
|
13503
|
+
throw new SessionNotFoundError(sessionId, "The session is closing");
|
|
13504
|
+
}
|
|
13505
|
+
let response;
|
|
13506
|
+
try {
|
|
13507
|
+
response = await Promise.race([
|
|
12641
13508
|
entry.connection.extMethod(
|
|
12642
13509
|
SERVE_CONTROL_EXT_METHODS.sessionRewind,
|
|
12643
13510
|
{
|
|
@@ -12646,92 +13513,98 @@ function createAcpSessionBridge(opts) {
|
|
|
12646
13513
|
rewindFiles: req.rewindFiles !== false
|
|
12647
13514
|
}
|
|
12648
13515
|
),
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
if (kind === "invalid_rewind_target") {
|
|
12663
|
-
throw new InvalidRewindTargetError(sessionId, msg);
|
|
13516
|
+
getTransportClosedReject(entry)
|
|
13517
|
+
]);
|
|
13518
|
+
} catch (err) {
|
|
13519
|
+
const data = err?.data;
|
|
13520
|
+
if (data && typeof data === "object" && "errorKind" in data) {
|
|
13521
|
+
const kind = data.errorKind;
|
|
13522
|
+
const msg = err?.message ?? "Rewind failed";
|
|
13523
|
+
if (kind === "session_busy") {
|
|
13524
|
+
throw new SessionBusyError(sessionId, msg);
|
|
13525
|
+
}
|
|
13526
|
+
if (kind === "invalid_rewind_target") {
|
|
13527
|
+
throw new InvalidRewindTargetError(sessionId, msg);
|
|
13528
|
+
}
|
|
12664
13529
|
}
|
|
13530
|
+
throw err;
|
|
12665
13531
|
}
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
const artifactSnapshotUnavailable = artifactSnapshotUnavailableReason(
|
|
12675
|
-
response
|
|
12676
|
-
);
|
|
12677
|
-
const beforeArtifacts = (await entry.artifacts.list()).artifacts;
|
|
12678
|
-
const shouldRestoreArtifactSnapshot = artifactSnapshot !== void 0 && artifactSnapshotUnavailable === void 0;
|
|
12679
|
-
const artifactRestoreWarnings = artifactSnapshotUnavailable !== void 0 ? [
|
|
12680
|
-
`artifact snapshot rebuild unavailable during rewind: ${artifactSnapshotUnavailable}`
|
|
12681
|
-
] : shouldRestoreArtifactSnapshot ? await entry.artifacts.restore(artifactSnapshot, {
|
|
12682
|
-
preserveLiveEphemeral: true
|
|
12683
|
-
}) : [];
|
|
12684
|
-
const artifactRestoreFailed = artifactRestoreWarnings.some(
|
|
12685
|
-
isArtifactRestoreFailureWarning
|
|
12686
|
-
);
|
|
12687
|
-
const shouldRecordArtifactSnapshot = shouldRestoreArtifactSnapshot && !artifactRestoreFailed;
|
|
12688
|
-
const artifactSnapshotWarnings = shouldRecordArtifactSnapshot ? await entry.artifacts.recordSnapshot() : [];
|
|
12689
|
-
const artifactWarnings = [
|
|
12690
|
-
...artifactRestoreWarnings,
|
|
12691
|
-
...artifactSnapshotWarnings
|
|
12692
|
-
];
|
|
12693
|
-
for (const warning of artifactRestoreWarnings) {
|
|
12694
|
-
writeStderrLine(
|
|
12695
|
-
`[artifacts] session=${entry.sessionId} action=rewind_restore_warning warning=${JSON.stringify(
|
|
12696
|
-
warning
|
|
12697
|
-
)}`
|
|
13532
|
+
entry.terminalTurnStatuses.clear();
|
|
13533
|
+
entry.enrichedTerminalPromptIds.clear();
|
|
13534
|
+
entry.rewindGeneration += 1;
|
|
13535
|
+
const targetTurnIndex = response["targetTurnIndex"] ?? 0;
|
|
13536
|
+
const filesChanged = response["filesChanged"] ?? [];
|
|
13537
|
+
const filesFailed = response["filesFailed"] ?? [];
|
|
13538
|
+
const artifactSnapshot = restoredArtifactSnapshotFromState(
|
|
13539
|
+
response
|
|
12698
13540
|
);
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
writeStderrLine(
|
|
12702
|
-
`[artifacts] session=${entry.sessionId} action=rewind_snapshot_warning warning=${JSON.stringify(
|
|
12703
|
-
warning
|
|
12704
|
-
)}`
|
|
13541
|
+
const artifactSnapshotUnavailable = artifactSnapshotUnavailableReason(
|
|
13542
|
+
response
|
|
12705
13543
|
);
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
|
|
12711
|
-
|
|
13544
|
+
const beforeArtifacts = (await entry.artifacts.list()).artifacts;
|
|
13545
|
+
const shouldRestoreArtifactSnapshot = artifactSnapshot !== void 0 && artifactSnapshotUnavailable === void 0;
|
|
13546
|
+
const artifactRestoreWarnings = artifactSnapshotUnavailable !== void 0 ? [
|
|
13547
|
+
`artifact snapshot rebuild unavailable during rewind: ${artifactSnapshotUnavailable}`
|
|
13548
|
+
] : shouldRestoreArtifactSnapshot ? await entry.artifacts.restore(artifactSnapshot, {
|
|
13549
|
+
preserveLiveEphemeral: true
|
|
13550
|
+
}) : [];
|
|
13551
|
+
const artifactRestoreFailed = artifactRestoreWarnings.some(
|
|
13552
|
+
isArtifactRestoreFailureWarning
|
|
13553
|
+
);
|
|
13554
|
+
const shouldRecordArtifactSnapshot = shouldRestoreArtifactSnapshot && !artifactRestoreFailed;
|
|
13555
|
+
const artifactSnapshotWarnings = shouldRecordArtifactSnapshot ? await entry.artifacts.recordSnapshot() : [];
|
|
13556
|
+
const artifactWarnings = [
|
|
13557
|
+
...artifactRestoreWarnings,
|
|
13558
|
+
...artifactSnapshotWarnings
|
|
13559
|
+
];
|
|
13560
|
+
for (const warning of artifactRestoreWarnings) {
|
|
13561
|
+
writeStderrLine(
|
|
13562
|
+
`[artifacts] session=${entry.sessionId} action=rewind_restore_warning warning=${JSON.stringify(
|
|
13563
|
+
warning
|
|
13564
|
+
)}`
|
|
13565
|
+
);
|
|
13566
|
+
}
|
|
13567
|
+
for (const warning of artifactSnapshotWarnings) {
|
|
13568
|
+
writeStderrLine(
|
|
13569
|
+
`[artifacts] session=${entry.sessionId} action=rewind_snapshot_warning warning=${JSON.stringify(
|
|
13570
|
+
warning
|
|
13571
|
+
)}`
|
|
13572
|
+
);
|
|
13573
|
+
}
|
|
13574
|
+
const afterArtifacts = (await entry.artifacts.list()).artifacts;
|
|
13575
|
+
publishArtifactChanges(
|
|
13576
|
+
entry,
|
|
13577
|
+
artifactReseedChanges(beforeArtifacts, afterArtifacts),
|
|
13578
|
+
originatorClientId
|
|
13579
|
+
);
|
|
13580
|
+
try {
|
|
13581
|
+
entry.events.publish({
|
|
13582
|
+
type: "session_rewound",
|
|
13583
|
+
data: {
|
|
13584
|
+
sessionId,
|
|
13585
|
+
promptId: req.promptId,
|
|
13586
|
+
targetTurnIndex,
|
|
13587
|
+
filesChanged,
|
|
13588
|
+
filesFailed,
|
|
13589
|
+
...artifactWarnings.length > 0 ? { warnings: artifactWarnings } : {}
|
|
13590
|
+
},
|
|
13591
|
+
...originatorClientId ? { originatorClientId } : {}
|
|
13592
|
+
});
|
|
13593
|
+
} catch {
|
|
13594
|
+
}
|
|
13595
|
+
return {
|
|
13596
|
+
rewound: filesFailed.length === 0,
|
|
13597
|
+
targetTurnIndex,
|
|
13598
|
+
filesChanged,
|
|
13599
|
+
filesFailed,
|
|
13600
|
+
...artifactWarnings.length > 0 ? { warnings: artifactWarnings } : {}
|
|
13601
|
+
};
|
|
13602
|
+
});
|
|
13603
|
+
entry.promptQueue = rewindResult.then(
|
|
13604
|
+
() => void 0,
|
|
13605
|
+
() => void 0
|
|
12712
13606
|
);
|
|
12713
|
-
|
|
12714
|
-
entry.events.publish({
|
|
12715
|
-
type: "session_rewound",
|
|
12716
|
-
data: {
|
|
12717
|
-
sessionId,
|
|
12718
|
-
promptId: req.promptId,
|
|
12719
|
-
targetTurnIndex,
|
|
12720
|
-
filesChanged,
|
|
12721
|
-
filesFailed,
|
|
12722
|
-
...artifactWarnings.length > 0 ? { warnings: artifactWarnings } : {}
|
|
12723
|
-
},
|
|
12724
|
-
...originatorClientId ? { originatorClientId } : {}
|
|
12725
|
-
});
|
|
12726
|
-
} catch {
|
|
12727
|
-
}
|
|
12728
|
-
return {
|
|
12729
|
-
rewound: filesFailed.length === 0,
|
|
12730
|
-
targetTurnIndex,
|
|
12731
|
-
filesChanged,
|
|
12732
|
-
filesFailed,
|
|
12733
|
-
...artifactWarnings.length > 0 ? { warnings: artifactWarnings } : {}
|
|
12734
|
-
};
|
|
13607
|
+
return rewindResult;
|
|
12735
13608
|
},
|
|
12736
13609
|
async manageMcpServer(serverName, action, originatorClientId) {
|
|
12737
13610
|
const info = await ensureChannel();
|
|
@@ -12862,7 +13735,7 @@ function createAcpSessionBridge(opts) {
|
|
|
12862
13735
|
]);
|
|
12863
13736
|
},
|
|
12864
13737
|
generateWorkspaceContent(prompt, signal, _originatorClientId) {
|
|
12865
|
-
const requestId =
|
|
13738
|
+
const requestId = randomUUID3();
|
|
12866
13739
|
const queue = new GenerationStreamQueue(
|
|
12867
13740
|
GENERATION_STREAM_QUEUE_CAPACITY
|
|
12868
13741
|
);
|
|
@@ -13041,6 +13914,11 @@ function createAcpSessionBridge(opts) {
|
|
|
13041
13914
|
closingChannel,
|
|
13042
13915
|
`force kill closing session ${JSON.stringify(sessionId)}`
|
|
13043
13916
|
);
|
|
13917
|
+
await releaseSessionMedia(sessionId).catch((releaseError) => {
|
|
13918
|
+
writeStderrLine(
|
|
13919
|
+
`qwen serve: failed to release media for killed session ${JSON.stringify(sessionId)}: ${releaseError instanceof Error ? releaseError.message : String(releaseError)}`
|
|
13920
|
+
);
|
|
13921
|
+
});
|
|
13044
13922
|
return true;
|
|
13045
13923
|
}
|
|
13046
13924
|
entry.closing = true;
|
|
@@ -13059,11 +13937,20 @@ function createAcpSessionBridge(opts) {
|
|
|
13059
13937
|
timeoutMs: initTimeoutMs
|
|
13060
13938
|
});
|
|
13061
13939
|
} catch (error) {
|
|
13940
|
+
if (isDefinitiveAcpRequestError(error)) {
|
|
13941
|
+
entry.closing = false;
|
|
13942
|
+
return false;
|
|
13943
|
+
}
|
|
13062
13944
|
if (ci) {
|
|
13063
13945
|
await killChannelWithLog(
|
|
13064
13946
|
ci,
|
|
13065
13947
|
`force kill session ${JSON.stringify(sessionId)}`
|
|
13066
13948
|
);
|
|
13949
|
+
await releaseSessionMedia(sessionId).catch((releaseError) => {
|
|
13950
|
+
writeStderrLine(
|
|
13951
|
+
`qwen serve: failed to release media for killed session ${JSON.stringify(sessionId)}: ${releaseError instanceof Error ? releaseError.message : String(releaseError)}`
|
|
13952
|
+
);
|
|
13953
|
+
});
|
|
13067
13954
|
return true;
|
|
13068
13955
|
}
|
|
13069
13956
|
entry.closing = false;
|
|
@@ -13100,6 +13987,11 @@ function createAcpSessionBridge(opts) {
|
|
|
13100
13987
|
} catch {
|
|
13101
13988
|
}
|
|
13102
13989
|
entry.events.close();
|
|
13990
|
+
await releaseSessionMedia(sessionId).catch((error) => {
|
|
13991
|
+
writeStderrLine(
|
|
13992
|
+
`qwen serve: failed to release media for killed session ${JSON.stringify(sessionId)}: ${error instanceof Error ? error.message : String(error)}`
|
|
13993
|
+
);
|
|
13994
|
+
});
|
|
13103
13995
|
if (ci && hasNoChannelWork(ci)) {
|
|
13104
13996
|
await reapPendingEmptyChannel(ci);
|
|
13105
13997
|
if (!ci.isDying) {
|
|
@@ -13204,6 +14096,8 @@ function createAcpSessionBridge(opts) {
|
|
|
13204
14096
|
) : Promise.resolve();
|
|
13205
14097
|
const teardownResults = await Promise.allSettled([
|
|
13206
14098
|
...channels.map((ci) => ci.channel.kill()),
|
|
14099
|
+
...[...retainedMedia.values()].map((store) => store.close()),
|
|
14100
|
+
mediaPutQueue,
|
|
13207
14101
|
...inFlightSessionAwaits,
|
|
13208
14102
|
...inFlightRestoreAwaits,
|
|
13209
14103
|
inFlightChannelAwait
|