@zubriq/code 0.19.8-1 → 0.19.9-1
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/dist/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
- package/dist/bundled/qc-helper/docs/features/channels/overview.md +23 -12
- package/dist/bundled/qc-helper/docs/features/channels/plugins.md +1 -0
- package/dist/bundled/qc-helper/docs/features/channels/wecom.md +111 -0
- package/dist/bundled/qc-helper/docs/features/hooks.md +36 -34
- package/dist/bundled/qc-helper/docs/features/memory.md +1 -1
- package/dist/bundled/qc-helper/docs/qwen-serve.md +17 -10
- package/dist/bundled/review/SKILL.md +6 -2
- package/dist/chunks/{MaxSizedBox-OWTCJQNO.js → MaxSizedBox-W6SAJMJC.js} +13 -11
- package/dist/chunks/{StandaloneSessionPicker-6NGEQFBH.js → StandaloneSessionPicker-YBKZZKIA.js} +28 -23
- package/dist/chunks/{acpAgent-XPRWSNOW.js → acpAgent-SQJQBOTS.js} +110 -80
- package/dist/chunks/{agent-TB6S4VXU.js → agent-QU7Q2RZN.js} +8 -8
- package/dist/chunks/{agent-headless-R3XYK5TT.js → agent-headless-PBHLWHND.js} +8 -8
- package/dist/chunks/{anthropicContentGenerator-FZQAEMYK.js → anthropicContentGenerator-52G6ZA3D.js} +31 -4
- package/dist/chunks/{artifact-tool-H2TNPNP5.js → artifact-tool-D233YJFH.js} +25 -6
- package/dist/chunks/{bridge-HVRG6SMU.js → bridge-LJLLDUMW.js} +17 -14
- package/dist/chunks/{ca-HCMB2I54.js → ca-MKD32FQL.js} +26 -1
- package/dist/chunks/{channel-worker-supervisor-B7MSMB5K.js → channel-worker-supervisor-NZQUOEFJ.js} +3 -3
- package/dist/chunks/{chunk-YRM6BC6H.js → chunk-27AYMAL6.js} +506 -63
- package/dist/chunks/{chunk-536GZ6UF.js → chunk-2MDC5WDB.js} +17 -111
- package/dist/chunks/{chunk-H3D6XAOL.js → chunk-2PRSBVPI.js} +3 -3
- package/dist/chunks/chunk-332PWN27.js +19 -0
- package/dist/chunks/{chunk-FVMWEHWU.js → chunk-3B26UVCX.js} +114 -12
- package/dist/chunks/{chunk-ZM5BPDXV.js → chunk-3F22JT4E.js} +1 -1
- package/dist/chunks/{chunk-W6RH6KHR.js → chunk-3GPVYALM.js} +4 -2
- package/dist/chunks/{chunk-G7ZG7CA6.js → chunk-3UP777ZS.js} +8 -7
- package/dist/chunks/{chunk-PA7QS4X5.js → chunk-43W4YSO6.js} +1 -12
- package/dist/chunks/{chunk-5EB2HK3X.js → chunk-4IK56VLC.js} +1 -1
- package/dist/chunks/{chunk-UE5TCZE6.js → chunk-5FAUIGXH.js} +5 -13
- package/dist/chunks/{chunk-VEB3NYSO.js → chunk-5MBO76SL.js} +5 -0
- package/dist/chunks/{chunk-PDITONOB.js → chunk-5MRUKUOG.js} +5347 -4132
- package/dist/chunks/{chunk-4UC3U66K.js → chunk-6EUMFVPJ.js} +5 -5
- package/dist/chunks/{chunk-YOGGIAGF.js → chunk-6JL5OVLX.js} +1 -1
- package/dist/chunks/{chunk-QG4ZO2EB.js → chunk-74E6VVF6.js} +11 -11
- package/dist/chunks/chunk-A2X3KLC3.js +3807 -0
- package/dist/chunks/{chunk-BA4HLTG2.js → chunk-B6B2MUUF.js} +5 -5
- package/dist/chunks/{chunk-XKYOIERV.js → chunk-BN5VYAOZ.js} +681 -1239
- package/dist/chunks/{chunk-IO76BGJ3.js → chunk-BYUA6YYS.js} +15 -9
- package/dist/chunks/{chunk-NCFY7PWS.js → chunk-CCGOFQV3.js} +51 -2
- package/dist/chunks/{chunk-66KNL43D.js → chunk-CD6USWHZ.js} +1 -1
- package/dist/chunks/{chunk-ZWSTIPSW.js → chunk-CEITMQ62.js} +2 -2
- package/dist/chunks/{chunk-7AQTBTVY.js → chunk-EJP6Z7NU.js} +4 -3
- package/dist/chunks/{chunk-RTW5ZXHO.js → chunk-EZTNYRHH.js} +6 -5
- package/dist/chunks/{chunk-MJQFA66Z.js → chunk-FAATDXYS.js} +308 -81
- package/dist/chunks/{chunk-DNV4FSN5.js → chunk-FBET5XZ2.js} +6 -4
- package/dist/chunks/{chunk-HTC4R67V.js → chunk-FES4YXJ3.js} +9 -9
- package/dist/chunks/{chunk-NBKE6QRZ.js → chunk-FHTUTVIQ.js} +10 -5
- package/dist/chunks/chunk-FII3C4E7.js +168 -0
- package/dist/chunks/{chunk-2NL7ED5Q.js → chunk-FV7425LN.js} +22 -1
- package/dist/chunks/{chunk-J6OET6C3.js → chunk-GAI76CFX.js} +4 -4
- package/dist/chunks/{chunk-B34OV7K2.js → chunk-GGQQA4JW.js} +13 -0
- package/dist/chunks/chunk-GLE2YUPU.js +34 -0
- package/dist/chunks/{chunk-X265R5C6.js → chunk-GN3F6PIU.js} +1 -1
- package/dist/chunks/{chunk-SM624MOZ.js → chunk-GWUN54UD.js} +1 -1
- package/dist/chunks/chunk-H3TELH3H.js +942 -0
- package/dist/chunks/{chunk-XZULYFIX.js → chunk-HD4DZI2L.js} +2 -2
- package/dist/chunks/{chunk-KLLLWQM2.js → chunk-HPQIVXSP.js} +1 -1
- package/dist/chunks/{chunk-WSVZFWN4.js → chunk-IBY3Q3HG.js} +693 -104
- package/dist/chunks/{chunk-JSEOX4CM.js → chunk-JGR6W4IX.js} +14 -8
- package/dist/chunks/chunk-K652V4NH.js +283 -0
- package/dist/chunks/{chunk-OCBJKHF2.js → chunk-KH2CZZDD.js} +2 -2
- package/dist/chunks/chunk-LGFAYIKX.js +115 -0
- package/dist/chunks/{chunk-QG5KDB6X.js → chunk-LZDW5TDV.js} +5 -5
- package/dist/chunks/{chunk-ENKWIF75.js → chunk-MA4AZNP7.js} +10 -10
- package/dist/chunks/{chunk-4RQIB5UZ.js → chunk-O2YT7VB4.js} +0 -34
- package/dist/chunks/{chunk-4KJ2BPIT.js → chunk-OACJLMLD.js} +2 -38
- package/dist/chunks/{chunk-ML2ZWH2K.js → chunk-PCWYMX57.js} +14 -153
- package/dist/chunks/{chunk-NHFBLJOI.js → chunk-Q3PQ5VGJ.js} +1 -1
- package/dist/chunks/{chunk-LGXBB2R2.js → chunk-QK3I36QG.js} +1 -1
- package/dist/chunks/chunk-RA7TR75G.js +8223 -0
- package/dist/chunks/{chunk-KSPVDFE4.js → chunk-SAIILPQ3.js} +0 -3
- package/dist/chunks/{chunk-DHKDK57Q.js → chunk-SNZPA74J.js} +146 -54
- package/dist/chunks/{chunk-PWR5MVM3.js → chunk-SSP3UT5C.js} +4 -4
- package/dist/chunks/{chunk-4LETJLG2.js → chunk-SUCRVT5L.js} +1 -1
- package/dist/chunks/{chunk-5YLZHETW.js → chunk-TRR5KGDN.js} +1 -1
- package/dist/chunks/chunk-UIDXQNMV.js +13 -0
- package/dist/chunks/{chunk-PIORL4OD.js → chunk-UKV3D7WB.js} +0 -44
- package/dist/chunks/chunk-UYNUIGUR.js +167 -0
- package/dist/chunks/chunk-V2TYBEWU.js +28 -0
- package/dist/chunks/chunk-V35MD7KN.js +13 -0
- package/dist/chunks/{chunk-N4HTVZDZ.js → chunk-VR3KCBHH.js} +1 -1
- package/dist/chunks/{chunk-APYUOROB.js → chunk-W4CTWW7M.js} +423 -61
- package/dist/chunks/{chunk-ABANKQYY.js → chunk-WJAW2O5H.js} +92 -465
- package/dist/chunks/{chunk-6RSBRKF5.js → chunk-WN4YJJGH.js} +2 -2
- package/dist/chunks/chunk-XNXVCNAT.js +88 -0
- package/dist/chunks/{chunk-TDGF35EN.js → chunk-XOHNA2S6.js} +1 -1
- package/dist/chunks/chunk-XQPMKWSV.js +487 -0
- package/dist/chunks/{chunk-4FQL7KUS.js → chunk-XWDHZP7P.js} +8 -8
- package/dist/chunks/{chunk-REPRY4F7.js → chunk-YCKKP4QA.js} +10 -10
- package/dist/chunks/{chunk-YNWQ3PUQ.js → chunk-YJWMOGGZ.js} +3 -3
- package/dist/chunks/{chunk-RFIL6REB.js → chunk-YKZIAK7C.js} +119 -29
- package/dist/chunks/{chunk-45YCXM2H.js → chunk-YZDBUH6S.js} +45 -9
- package/dist/chunks/chunk-Z3I3QJK3.js +47 -0
- package/dist/chunks/{chunk-G23FFNLT.js → chunk-ZDGPPCTW.js} +20 -8
- package/dist/chunks/chunk-ZL5HN75Q.js +61 -0
- package/dist/chunks/{chunk-IQX5S2RS.js → chunk-ZL7JCYWM.js} +66 -7
- package/dist/chunks/{computer-use-A72BECH4.js → computer-use-4B45EG2F.js} +8 -8
- package/dist/chunks/{contextCommand-RREXA4B7.js → contextCommand-GIVRWNTS.js} +12 -11
- package/dist/chunks/{cron-create-DDYU4DIR.js → cron-create-JSXEIPVS.js} +1 -1
- package/dist/chunks/{cron-delete-DFKOUZWN.js → cron-delete-OIFVEPGU.js} +1 -1
- package/dist/chunks/{cron-list-ME5QGAR5.js → cron-list-D4ZX4IOE.js} +1 -1
- package/dist/chunks/{daemon-XWG2EGFX.js → daemon-WPAENEBW.js} +71 -3
- package/dist/chunks/{daemon-status-provider-Y6AFXTET.js → daemon-status-provider-WBOAMCHE.js} +20 -17
- package/dist/chunks/{de-PLLFDERI.js → de-ZFPPQVSF.js} +26 -1
- package/dist/chunks/{dist-LPVU3L2M.js → dist-BEXOZXLQ.js} +6 -3792
- package/dist/chunks/{dist-7GU63KI5.js → dist-E6UANPIM.js} +1 -1
- package/dist/chunks/{dist-VHBP2PIG.js → dist-H2AEJCZ5.js} +2 -2
- package/dist/chunks/{dist-3UDX5T4T.js → dist-O2IRTRPP.js} +1 -1
- package/dist/chunks/dist-SCFLLYMK.js +3217 -0
- package/dist/chunks/{dist-H4HHZYCI.js → dist-Z34QPAQW.js} +2 -2
- package/dist/chunks/{earlyInputCapture-OAHBOGOO.js → earlyInputCapture-JWMCAJZR.js} +8 -8
- package/dist/chunks/{edit-SFYW3FOV.js → edit-O5FUVHBE.js} +9 -9
- package/dist/chunks/{en-AXARKOWO.js → en-N4EPZAQI.js} +31 -2
- package/dist/chunks/{enter-worktree-LUPPQ2NH.js → enter-worktree-LOJFRC3D.js} +8 -8
- package/dist/chunks/{enterPlanMode-44GEN5U6.js → enterPlanMode-VS3FAUPX.js} +8 -8
- package/dist/chunks/environment-WKW5TLSH.js +90 -0
- package/dist/chunks/{errors-H3Q3W3DL.js → errors-LEZXHJMR.js} +10 -10
- package/dist/chunks/{exit-worktree-34CVVWT4.js → exit-worktree-RN2NXRMP.js} +8 -8
- package/dist/chunks/{exitPlanMode-5G5BHNUP.js → exitPlanMode-EPC424I4.js} +8 -8
- package/dist/chunks/{fast-path-7PKGFBRM.js → fast-path-UUPAFOSQ.js} +12 -3
- package/dist/chunks/{fast-path-settings-RCRXH2JG.js → fast-path-settings-7RIFI3PK.js} +3 -2
- package/dist/chunks/{fr-MBMNQSQ6.js → fr-5WWMY53B.js} +30 -1
- package/dist/chunks/{gemini-2II6JH4H.js → gemini-QCKK4XNU.js} +438 -265
- package/dist/chunks/{geminiContentGenerator-SWEJVOC4.js → geminiContentGenerator-DX4SRXJA.js} +1 -1
- package/dist/chunks/{glob-5DFC7DXW.js → glob-4URMJWRX.js} +8 -8
- package/dist/chunks/{grep-QYVXGRRJ.js → grep-AEQB5KED.js} +8 -8
- package/dist/chunks/handleAutoUpdate-Y4YNG34Y.js +65 -0
- package/dist/chunks/{initializer-XX3UGUHE.js → initializer-NDEBMSOG.js} +17 -13
- package/dist/chunks/{ja-HFV5QCHR.js → ja-CUHZOLEJ.js} +30 -1
- package/dist/chunks/{list-AX5FWBVC.js → list-VSCBNOWT.js} +17 -15
- package/dist/chunks/{loadedSettingsAdapter-ISOM6GJ7.js → loadedSettingsAdapter-FDO752BA.js} +15 -13
- package/dist/chunks/{loop-wakeup-ZW5P6VPY.js → loop-wakeup-OHWEMFP5.js} +2 -2
- package/dist/chunks/{ls-L654WOAT.js → ls-7MFU2QYW.js} +1 -1
- package/dist/chunks/{lsp-M35KE54Y.js → lsp-XHDTPTGV.js} +2 -4
- package/dist/chunks/{mcp-74F6725E.js → mcp-MLPWTHUV.js} +15 -13
- package/dist/chunks/{monitor-W4WRSC2C.js → monitor-WCVHIJUJ.js} +16 -11
- package/dist/chunks/{nonInteractiveCli-4QMV6C4J.js → nonInteractiveCli-32HZK274.js} +52 -44
- package/dist/chunks/{notebook-edit-XBZEIP42.js → notebook-edit-NPOMPKS4.js} +9 -9
- package/dist/chunks/{openaiContentGenerator-RTUJDESE.js → openaiContentGenerator-6AIBSRQK.js} +6 -6
- package/dist/chunks/{pidfile-YWSGNTPK.js → pidfile-7Y3QEDSZ.js} +8 -8
- package/dist/chunks/{pt-2THT3YHA.js → pt-OLYN42DS.js} +26 -1
- package/dist/chunks/{qwenContentGenerator-4ZFYAZLY.js → qwenContentGenerator-OUYOAYT4.js} +10 -10
- package/dist/chunks/{read-file-D7DKDIAC.js → read-file-EESFA24L.js} +3 -3
- package/dist/chunks/{record-artifact-PP3LKHTS.js → record-artifact-SQ2OKRJW.js} +3 -3
- package/dist/chunks/{ripGrep-KG7JYNER.js → ripGrep-DLYV7ZZG.js} +8 -8
- package/dist/chunks/{ru-PER5I4OI.js → ru-MKM2HFDS.js} +26 -1
- package/dist/chunks/{run-qwen-serve-XGJSNF6S.js → run-qwen-serve-WUEHQROF.js} +602 -143
- package/dist/chunks/{scheduler-MOLWOE4G.js → scheduler-SK4Y66V4.js} +8 -8
- package/dist/chunks/{send-message-OA6MV4EU.js → send-message-76GT3JMC.js} +1 -1
- package/dist/chunks/{serve-4ZNVPYND.js → serve-UCDGVZFI.js} +17 -14
- package/dist/chunks/{server-ACWDFHIF.js → server-FVGFFVZ4.js} +1394 -328
- package/dist/chunks/{session-VYO2GRO2.js → session-RIGKDMGR.js} +53 -45
- package/dist/chunks/{settings-4J2O3K22.js → settings-LVFFGXGE.js} +24 -20
- package/dist/chunks/{shell-RKERJYXR.js → shell-PAWNAFYN.js} +8 -8
- package/dist/chunks/{skill-JYACZJ5V.js → skill-5YIN3Z6Y.js} +15 -5
- package/dist/chunks/{spawnChannel-BA3U3RGX.js → spawnChannel-KIMZHWNR.js} +10 -10
- package/dist/chunks/{src-3P337V4P.js → src-BIWCD3VX.js} +21 -9
- package/dist/chunks/{startInteractiveUI-SUSZ6FWB.js → startInteractiveUI-AFXLGUFI.js} +33759 -41620
- package/dist/chunks/{task-create-RPFZNB4B.js → task-create-WCHTB435.js} +2 -2
- package/dist/chunks/{task-update-5WUG5MVQ.js → task-update-XYWMHJGJ.js} +2 -2
- package/dist/chunks/{team-create-YVWGRZEA.js → team-create-26WOMISV.js} +8 -8
- package/dist/chunks/{team-plan-approval-VRF54TTI.js → team-plan-approval-B5XB6UQC.js} +8 -8
- package/dist/chunks/{theme-manager-JW2KOACL.js → theme-manager-4TJ5TEFD.js} +8 -8
- package/dist/chunks/{tool-search-KUSMAZBN.js → tool-search-FFU63E6M.js} +6 -23
- package/dist/chunks/total-session-admission-JOD7SMPJ.js +72 -0
- package/dist/chunks/{trustedFolders-ERGSUCDK.js → trustedFolders-IJ2QHXSC.js} +9 -9
- package/dist/chunks/updateCheck-5Z25DCBP.js +65 -0
- package/dist/chunks/{validateNonInterActiveAuth-DDI62H5X.js → validateNonInterActiveAuth-G5EY47DE.js} +49 -41
- package/dist/chunks/{version-VB3AHVUF.js → version-LGO3GOKQ.js} +2 -1
- package/dist/chunks/{workflow-WINKRCI4.js → workflow-ZTK3WT3D.js} +9 -9
- package/dist/chunks/{workspace-providers-status-ZVZPXKSO.js → workspace-providers-status-YMPTRKW2.js} +18 -15
- package/dist/chunks/workspace-registry-NBUL6LBH.js +74 -0
- package/dist/chunks/{workspace-service-GAS2LV2P.js → workspace-service-V6G2RCD4.js} +21 -19
- package/dist/chunks/{workspace-skills-status-4WGKYJVA.js → workspace-skills-status-ZCW44BCH.js} +16 -14
- package/dist/chunks/{write-file-UTLKVZNN.js → write-file-4FUTAEW6.js} +9 -9
- package/dist/chunks/{zh-RS3HZHFH.js → zh-J4F6QWQV.js} +31 -2
- package/dist/chunks/{zh-TW-L5GRQ4S4.js → zh-TW-XVDWOLSW.js} +31 -2
- package/dist/cli.js +11 -11
- package/dist/locales/ca.js +30 -0
- package/dist/locales/de.js +30 -0
- package/dist/locales/en.js +38 -2
- package/dist/locales/fr.js +36 -0
- package/dist/locales/ja.js +36 -0
- package/dist/locales/pt.js +30 -0
- package/dist/locales/ru.js +30 -0
- package/dist/locales/zh-TW.js +38 -2
- package/dist/locales/zh.js +38 -2
- package/dist/package.json +3 -3
- package/dist/web-shell/assets/{arc-C6tzvtOa.js → arc-BWyoJpY2.js} +1 -1
- package/dist/web-shell/assets/{architectureDiagram-3BPJPVTR-DSYQFGn9.js → architectureDiagram-3BPJPVTR-BT0mGrz2.js} +1 -1
- package/dist/web-shell/assets/{blockDiagram-GPEHLZMM-CHjBdXAD.js → blockDiagram-GPEHLZMM-BLgUWvyf.js} +1 -1
- package/dist/web-shell/assets/{c4Diagram-AAUBKEIU-BQzK6Yyb.js → c4Diagram-AAUBKEIU-DYx9M7oU.js} +1 -1
- package/dist/web-shell/assets/channel-wmPUGHtg.js +1 -0
- package/dist/web-shell/assets/{chunk-2J33WTMH-hpP2p3Ij.js → chunk-2J33WTMH-CfMHWbuZ.js} +1 -1
- package/dist/web-shell/assets/{chunk-4BX2VUAB-B5KtK1JJ.js → chunk-4BX2VUAB-B1URoqEV.js} +1 -1
- package/dist/web-shell/assets/{chunk-55IACEB6-BDv6Mfr2.js → chunk-55IACEB6-DAIaM4QF.js} +1 -1
- package/dist/web-shell/assets/{chunk-727SXJPM-BevPWfrX.js → chunk-727SXJPM-B2X34knw.js} +1 -1
- package/dist/web-shell/assets/{chunk-AQP2D5EJ-ChDrz2ad.js → chunk-AQP2D5EJ-Cif-zLTQ.js} +1 -1
- package/dist/web-shell/assets/{chunk-FMBD7UC4-ClMdVSDs.js → chunk-FMBD7UC4-H18WCXdY.js} +1 -1
- package/dist/web-shell/assets/{chunk-ND2GUHAM-BceV8kZS.js → chunk-ND2GUHAM-YFtetHi0.js} +1 -1
- package/dist/web-shell/assets/{chunk-QZHKN3VN-DtyK2wwc.js → chunk-QZHKN3VN-By2hiH3r.js} +1 -1
- package/dist/web-shell/assets/classDiagram-4FO5ZUOK-BA2ljEjW.js +1 -0
- package/dist/web-shell/assets/classDiagram-v2-Q7XG4LA2-BA2ljEjW.js +1 -0
- package/dist/web-shell/assets/{cose-bilkent-S5V4N54A-BGMsqwmE.js → cose-bilkent-S5V4N54A-VrcnnLZu.js} +1 -1
- package/dist/web-shell/assets/{dagre-BM42HDAG-C-71clpF.js → dagre-BM42HDAG-CGo-IaVV.js} +1 -1
- package/dist/web-shell/assets/{diagram-2AECGRRQ-WIzzlkec.js → diagram-2AECGRRQ-Dl4QjzIB.js} +1 -1
- package/dist/web-shell/assets/{diagram-5GNKFQAL-CtnhZUP1.js → diagram-5GNKFQAL-qMLmsO0u.js} +1 -1
- package/dist/web-shell/assets/{diagram-KO2AKTUF-CS_IUezp.js → diagram-KO2AKTUF-CHlmuxPI.js} +1 -1
- package/dist/web-shell/assets/{diagram-LMA3HP47-BQnGRwN9.js → diagram-LMA3HP47-BUwU3GwT.js} +1 -1
- package/dist/web-shell/assets/{diagram-OG6HWLK6-By2VIocq.js → diagram-OG6HWLK6-HEhwPDUM.js} +1 -1
- package/dist/web-shell/assets/{erDiagram-TEJ5UH35-Dy8WeNkr.js → erDiagram-TEJ5UH35-1n0llBmM.js} +1 -1
- package/dist/web-shell/assets/{flowDiagram-I6XJVG4X-Diu_4y0w.js → flowDiagram-I6XJVG4X-BN74uMnt.js} +1 -1
- package/dist/web-shell/assets/{ganttDiagram-6RSMTGT7-CH8euujP.js → ganttDiagram-6RSMTGT7-BoOq78i3.js} +1 -1
- package/dist/web-shell/assets/{gitGraphDiagram-PVQCEYII-DHiObZq1.js → gitGraphDiagram-PVQCEYII-CN8b00c8.js} +1 -1
- package/dist/web-shell/assets/index-CNwoO1Cn.js +783 -0
- package/dist/web-shell/assets/index-CWQ0z6kZ.css +5 -0
- package/dist/web-shell/assets/{infoDiagram-5YYISTIA-CvC9A6fh.js → infoDiagram-5YYISTIA-CCurnIna.js} +1 -1
- package/dist/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BK46kC4E.js → ishikawaDiagram-YF4QCWOH-AwuRqdUP.js} +1 -1
- package/dist/web-shell/assets/{journeyDiagram-JHISSGLW-B2TIiKq4.js → journeyDiagram-JHISSGLW-B7IICk-E.js} +1 -1
- package/dist/web-shell/assets/{kanban-definition-UN3LZRKU-Bh0WAulO.js → kanban-definition-UN3LZRKU-BYF0OKhx.js} +1 -1
- package/dist/web-shell/assets/{linear-Bxe9SHMk.js → linear-GWWguGfD.js} +1 -1
- package/dist/web-shell/assets/{mermaid.core-B1Pv6D5B.js → mermaid.core-JqtkxvCl.js} +5 -5
- package/dist/web-shell/assets/{mindmap-definition-RKZ34NQL-Bz0joLH8.js → mindmap-definition-RKZ34NQL-B0MmHsZ6.js} +1 -1
- package/dist/web-shell/assets/{pieDiagram-4H26LBE5-CnN4x-VS.js → pieDiagram-4H26LBE5-DhImUZLQ.js} +1 -1
- package/dist/web-shell/assets/{quadrantDiagram-W4KKPZXB-BYWD4xO4.js → quadrantDiagram-W4KKPZXB-DGeSC3DT.js} +1 -1
- package/dist/web-shell/assets/{requirementDiagram-4Y6WPE33-B4MEhI9h.js → requirementDiagram-4Y6WPE33-DkspY6Re.js} +1 -1
- package/dist/web-shell/assets/{sankeyDiagram-5OEKKPKP-Dk_FgKLp.js → sankeyDiagram-5OEKKPKP-CaOofS2x.js} +1 -1
- package/dist/web-shell/assets/{sequenceDiagram-3UESZ5HK-B4ksiBZQ.js → sequenceDiagram-3UESZ5HK-DFQ_kFnN.js} +1 -1
- package/dist/web-shell/assets/{stateDiagram-AJRCARHV-CYf0xSPl.js → stateDiagram-AJRCARHV-D3snw0Tz.js} +1 -1
- package/dist/web-shell/assets/stateDiagram-v2-BHNVJYJU-BbSm_9d0.js +1 -0
- package/dist/web-shell/assets/{timeline-definition-PNZ67QCA-0CXeWHNY.js → timeline-definition-PNZ67QCA-l4zH8nLM.js} +1 -1
- package/dist/web-shell/assets/{vennDiagram-CIIHVFJN-DHoYY9v2.js → vennDiagram-CIIHVFJN-BnRlA98M.js} +1 -1
- package/dist/web-shell/assets/{wardley-L42UT6IY-D_65qshr.js → wardley-L42UT6IY-BS0xUdmd.js} +1 -1
- package/dist/web-shell/assets/{wardleyDiagram-YWT4CUSO-Cv90x1sd.js → wardleyDiagram-YWT4CUSO-DKGBUWyQ.js} +1 -1
- package/dist/web-shell/assets/{xychartDiagram-2RQKCTM6-5FQCYJyh.js → xychartDiagram-2RQKCTM6-DVb2HuOB.js} +1 -1
- package/dist/web-shell/index.html +2 -2
- package/package.json +3 -2
- package/dist/web-shell/assets/channel-V-ZaJrA6.js +0 -1
- package/dist/web-shell/assets/classDiagram-4FO5ZUOK-s-H0snGT.js +0 -1
- package/dist/web-shell/assets/classDiagram-v2-Q7XG4LA2-s-H0snGT.js +0 -1
- package/dist/web-shell/assets/index-DW75jq0K.css +0 -5
- package/dist/web-shell/assets/index-tiCo0xbZ.js +0 -779
- package/dist/web-shell/assets/stateDiagram-v2-BHNVJYJU-CMtrFRUb.js +0 -1
|
@@ -77,6 +77,7 @@ __name(getGlobalQwenDir, "getGlobalQwenDir");
|
|
|
77
77
|
// packages/channels/base/dist/AcpBridge.js
|
|
78
78
|
init_esbuild_shims();
|
|
79
79
|
import { spawn } from "node:child_process";
|
|
80
|
+
import { randomUUID } from "node:crypto";
|
|
80
81
|
import { Readable, Writable } from "node:stream";
|
|
81
82
|
import { EventEmitter } from "node:events";
|
|
82
83
|
|
|
@@ -240,6 +241,7 @@ __name(readId, "readId");
|
|
|
240
241
|
// packages/channels/base/dist/AcpBridge.js
|
|
241
242
|
var MID_TURN_QUEUE_DRAIN_METHOD = "craft/drainMidTurnQueue";
|
|
242
243
|
var ACP_EVENT_LOOP_STALL_RESTART_MS = 5 * 60 * 1e3;
|
|
244
|
+
var ACP_PERMISSION_RESPONSE_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
243
245
|
var ACP_EVENT_LOOP_STALL_RE = /^\[perf\] acp agent event loop stall: max=(\d+(?:\.\d+)?)ms/m;
|
|
244
246
|
function readAvailableCommandAltNames(raw) {
|
|
245
247
|
if (typeof raw !== "object" || raw === null)
|
|
@@ -266,6 +268,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
266
268
|
channelLoopToolHandlers = [];
|
|
267
269
|
channelLoopMcpRegistered = false;
|
|
268
270
|
channelLoopMcpRegistration = null;
|
|
271
|
+
pendingPermissions = /* @__PURE__ */ new Map();
|
|
269
272
|
constructor(options) {
|
|
270
273
|
super();
|
|
271
274
|
this.options = options;
|
|
@@ -292,7 +295,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
292
295
|
this.child.stderr?.on("data", (data) => {
|
|
293
296
|
const msg = data.toString().trim();
|
|
294
297
|
if (msg) {
|
|
295
|
-
process.stderr.write(`[AcpBridge] ${msg}
|
|
298
|
+
process.stderr.write(`[AcpBridge] ${sanitizeLogText(msg, 4096)}
|
|
296
299
|
`);
|
|
297
300
|
this.maybeKillOnEventLoopStall(msg);
|
|
298
301
|
}
|
|
@@ -300,6 +303,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
300
303
|
this.child.on("exit", (code, signal) => {
|
|
301
304
|
process.stderr.write(`[AcpBridge] Process exited (code=${code}, signal=${signal})
|
|
302
305
|
`);
|
|
306
|
+
this.resolvePendingPermissions();
|
|
303
307
|
this.connection = null;
|
|
304
308
|
this.child = null;
|
|
305
309
|
this.emit("disconnected", code, signal);
|
|
@@ -316,11 +320,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
316
320
|
this.handleSessionUpdate(params);
|
|
317
321
|
return Promise.resolve();
|
|
318
322
|
}, "sessionUpdate"),
|
|
319
|
-
requestPermission: /* @__PURE__ */ __name(async (params) =>
|
|
320
|
-
const options = Array.isArray(params.options) ? params.options : [];
|
|
321
|
-
const optionId = options.find((o) => o.optionId === "proceed_once")?.optionId || options[0]?.optionId || "proceed_once";
|
|
322
|
-
return { outcome: { outcome: "selected", optionId } };
|
|
323
|
-
}, "requestPermission"),
|
|
323
|
+
requestPermission: /* @__PURE__ */ __name(async (params) => this.requestPermission(params), "requestPermission"),
|
|
324
324
|
extMethod: /* @__PURE__ */ __name(async (method, params) => this.handleExtMethod(method, params), "extMethod"),
|
|
325
325
|
extNotification: /* @__PURE__ */ __name(async () => {
|
|
326
326
|
}, "extNotification")
|
|
@@ -387,9 +387,28 @@ var AcpBridge = class extends EventEmitter {
|
|
|
387
387
|
}
|
|
388
388
|
async cancelSession(sessionId) {
|
|
389
389
|
const conn = this.ensureConnection();
|
|
390
|
-
|
|
390
|
+
try {
|
|
391
|
+
await conn.cancel({ sessionId });
|
|
392
|
+
} finally {
|
|
393
|
+
this.resolvePendingPermissions(sessionId);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async respondToPermission(requestId, response) {
|
|
397
|
+
const pending = this.pendingPermissions.get(requestId);
|
|
398
|
+
if (!pending) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
clearTimeout(pending.timeout);
|
|
402
|
+
this.pendingPermissions.delete(requestId);
|
|
403
|
+
pending.resolve(response);
|
|
404
|
+
this.emit("permissionResolved", {
|
|
405
|
+
requestId,
|
|
406
|
+
outcome: response.outcome
|
|
407
|
+
});
|
|
408
|
+
return true;
|
|
391
409
|
}
|
|
392
410
|
stop() {
|
|
411
|
+
this.resolvePendingPermissions();
|
|
393
412
|
if (this.child) {
|
|
394
413
|
this.child.kill();
|
|
395
414
|
this.child = null;
|
|
@@ -445,6 +464,53 @@ var AcpBridge = class extends EventEmitter {
|
|
|
445
464
|
}
|
|
446
465
|
return this.connection;
|
|
447
466
|
}
|
|
467
|
+
requestPermission(request) {
|
|
468
|
+
const requestId = `acp-permission-${randomUUID()}`;
|
|
469
|
+
const sessionId = typeof request.sessionId === "string" && request.sessionId.length > 0 ? request.sessionId : request.toolCall.toolCallId;
|
|
470
|
+
return new Promise((resolve2) => {
|
|
471
|
+
const timeout = setTimeout(() => {
|
|
472
|
+
const pending = this.pendingPermissions.get(requestId);
|
|
473
|
+
if (!pending) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
process.stderr.write(`[AcpBridge] permission request ${sanitizeLogText(requestId, 128)} timed out after ${ACP_PERMISSION_RESPONSE_TIMEOUT_MS}ms (session=${sanitizeLogText(pending.sessionId, 128)})
|
|
477
|
+
`);
|
|
478
|
+
this.pendingPermissions.delete(requestId);
|
|
479
|
+
const response = {
|
|
480
|
+
outcome: { outcome: "cancelled" }
|
|
481
|
+
};
|
|
482
|
+
pending.resolve(response);
|
|
483
|
+
this.emit("permissionResolved", {
|
|
484
|
+
requestId,
|
|
485
|
+
outcome: response.outcome
|
|
486
|
+
});
|
|
487
|
+
}, ACP_PERMISSION_RESPONSE_TIMEOUT_MS);
|
|
488
|
+
timeout.unref?.();
|
|
489
|
+
this.pendingPermissions.set(requestId, { sessionId, resolve: resolve2, timeout });
|
|
490
|
+
this.emit("permissionRequest", {
|
|
491
|
+
requestId,
|
|
492
|
+
sessionId,
|
|
493
|
+
request
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
resolvePendingPermissions(sessionId) {
|
|
498
|
+
const response = {
|
|
499
|
+
outcome: { outcome: "cancelled" }
|
|
500
|
+
};
|
|
501
|
+
for (const [requestId, pending] of this.pendingPermissions) {
|
|
502
|
+
if (sessionId !== void 0 && pending.sessionId !== sessionId) {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
clearTimeout(pending.timeout);
|
|
506
|
+
this.pendingPermissions.delete(requestId);
|
|
507
|
+
pending.resolve(response);
|
|
508
|
+
this.emit("permissionResolved", {
|
|
509
|
+
requestId,
|
|
510
|
+
outcome: response.outcome
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
}
|
|
448
514
|
maybeKillOnEventLoopStall(stderr) {
|
|
449
515
|
const match = ACP_EVENT_LOOP_STALL_RE.exec(stderr);
|
|
450
516
|
if (!match)
|
|
@@ -1237,6 +1303,36 @@ var GroupGate = class {
|
|
|
1237
1303
|
}
|
|
1238
1304
|
};
|
|
1239
1305
|
|
|
1306
|
+
// packages/channels/base/dist/DmGate.js
|
|
1307
|
+
init_esbuild_shims();
|
|
1308
|
+
var DmGate = class {
|
|
1309
|
+
static {
|
|
1310
|
+
__name(this, "DmGate");
|
|
1311
|
+
}
|
|
1312
|
+
policy;
|
|
1313
|
+
constructor(policy = "open") {
|
|
1314
|
+
this.policy = policy;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* DM check: policy gating for private/non-group messages.
|
|
1318
|
+
* Evaluation order:
|
|
1319
|
+
* 1. Group messages bypass this gate (handled by GroupGate)
|
|
1320
|
+
* 2. dmPolicy (disabled → drop)
|
|
1321
|
+
*
|
|
1322
|
+
* Symmetric with GroupGate — GroupGate owns group messages,
|
|
1323
|
+
* DmGate owns DM messages.
|
|
1324
|
+
*/
|
|
1325
|
+
check(envelope) {
|
|
1326
|
+
if (envelope.isGroup) {
|
|
1327
|
+
return { allowed: true };
|
|
1328
|
+
}
|
|
1329
|
+
if (this.policy === "disabled") {
|
|
1330
|
+
return { allowed: false, reason: "disabled" };
|
|
1331
|
+
}
|
|
1332
|
+
return { allowed: true };
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1240
1336
|
// packages/channels/base/dist/group-history-store.js
|
|
1241
1337
|
init_esbuild_shims();
|
|
1242
1338
|
import { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -2267,6 +2363,66 @@ function truncateError(message) {
|
|
|
2267
2363
|
}
|
|
2268
2364
|
__name(truncateError, "truncateError");
|
|
2269
2365
|
|
|
2366
|
+
// packages/channels/base/dist/channel-memory-intent.js
|
|
2367
|
+
init_esbuild_shims();
|
|
2368
|
+
var REMEMBER_PATTERNS = [
|
|
2369
|
+
/^记住[::]\s*(.+)$/su,
|
|
2370
|
+
/^记一下[::,,]?\s*(.+)$/su,
|
|
2371
|
+
/^帮我记一下[::,,]?\s*(.+)$/su,
|
|
2372
|
+
/^帮我记住[::,,]?\s*(.+)$/su,
|
|
2373
|
+
/^以后记住[::,,]?\s*(.+)$/su,
|
|
2374
|
+
/^remember:\s*(.+)$/isu
|
|
2375
|
+
];
|
|
2376
|
+
var LIST_PATTERNS = [
|
|
2377
|
+
/^你现在记住了什么[??]?$/u,
|
|
2378
|
+
/^查看记忆$/u,
|
|
2379
|
+
/^当前记忆$/u,
|
|
2380
|
+
/^这个聊天你记住了什么[??]?$/u,
|
|
2381
|
+
/^what do you remember[??]?$/iu
|
|
2382
|
+
];
|
|
2383
|
+
var CLEAR_REQUEST_PATTERNS = [
|
|
2384
|
+
/^清空记忆$/u,
|
|
2385
|
+
/^清除记忆$/u,
|
|
2386
|
+
/^忘掉这个聊天的所有记忆$/u,
|
|
2387
|
+
/^把.+的?记忆清空$/u,
|
|
2388
|
+
/^clear memory$/iu
|
|
2389
|
+
];
|
|
2390
|
+
var CLEAR_CONFIRM_PATTERNS = [
|
|
2391
|
+
/^确认清空记忆$/u,
|
|
2392
|
+
/^确认清除记忆$/u,
|
|
2393
|
+
/^confirm clear memory$/iu
|
|
2394
|
+
];
|
|
2395
|
+
function parseChannelMemoryIntent(text) {
|
|
2396
|
+
const trimmed = text.replace(PROMPT_UNSAFE_INVISIBLES, "").trim();
|
|
2397
|
+
if (!trimmed || trimmed.startsWith("/")) {
|
|
2398
|
+
return null;
|
|
2399
|
+
}
|
|
2400
|
+
for (const pattern of CLEAR_CONFIRM_PATTERNS) {
|
|
2401
|
+
if (pattern.test(trimmed)) {
|
|
2402
|
+
return { kind: "clear_confirm" };
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
for (const pattern of CLEAR_REQUEST_PATTERNS) {
|
|
2406
|
+
if (pattern.test(trimmed)) {
|
|
2407
|
+
return { kind: "clear_request" };
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
for (const pattern of LIST_PATTERNS) {
|
|
2411
|
+
if (pattern.test(trimmed)) {
|
|
2412
|
+
return { kind: "list" };
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
for (const pattern of REMEMBER_PATTERNS) {
|
|
2416
|
+
const match = trimmed.match(pattern);
|
|
2417
|
+
const remembered = match?.[1]?.replace(PROMPT_UNSAFE_INVISIBLES, "").trim();
|
|
2418
|
+
if (remembered) {
|
|
2419
|
+
return { kind: "remember", text: remembered };
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
return null;
|
|
2423
|
+
}
|
|
2424
|
+
__name(parseChannelMemoryIntent, "parseChannelMemoryIntent");
|
|
2425
|
+
|
|
2270
2426
|
// packages/channels/base/dist/ChannelBase.js
|
|
2271
2427
|
var CLEAR_CANCEL_TIMEOUT_MS = 3e3;
|
|
2272
2428
|
var GROUP_HISTORY_CONTEXT_MARKER = "[Chat messages since your last reply - for context]";
|
|
@@ -2274,6 +2430,8 @@ var CURRENT_MESSAGE_MARKER = "[Current message - respond to this]";
|
|
|
2274
2430
|
var GROUP_HISTORY_ENTRY_TEXT_LIMIT = 1e3;
|
|
2275
2431
|
var GROUP_HISTORY_ENTRY_METADATA_LIMIT = 256;
|
|
2276
2432
|
var LOOP_CANCEL_GRACE_MS = 5e3;
|
|
2433
|
+
var CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE = 0.7;
|
|
2434
|
+
var CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(记住|记得|记一下|记忆|忘掉|忘记|清空|清除|删除|保存|remember|memory|forget)/iu;
|
|
2277
2435
|
var LOOP_TIMED_OUT_MESSAGE = "loop timed out";
|
|
2278
2436
|
var COMMAND_TOKEN_CHARS = "a-zA-Z0-9_:-";
|
|
2279
2437
|
var PARSE_COMMAND_RE = new RegExp(`^\\/([${COMMAND_TOKEN_CHARS}]+)(?:@\\S+)?\\s*(.*)`, "s");
|
|
@@ -2297,6 +2455,7 @@ var ChannelBase = class {
|
|
|
2297
2455
|
config;
|
|
2298
2456
|
bridge;
|
|
2299
2457
|
groupGate;
|
|
2458
|
+
dmGate;
|
|
2300
2459
|
gate;
|
|
2301
2460
|
router;
|
|
2302
2461
|
name;
|
|
@@ -2306,6 +2465,7 @@ var ChannelBase = class {
|
|
|
2306
2465
|
/** Resolved proxy URL, available to subclasses for adapter-specific clients. */
|
|
2307
2466
|
proxy;
|
|
2308
2467
|
channelMemory;
|
|
2468
|
+
memoryIntentClassifier;
|
|
2309
2469
|
groupHistory;
|
|
2310
2470
|
loopController;
|
|
2311
2471
|
instructedSessions = /* @__PURE__ */ new Set();
|
|
@@ -2319,16 +2479,29 @@ var ChannelBase = class {
|
|
|
2319
2479
|
* so a cleared session can't be resurrected by an already-queued prompt.
|
|
2320
2480
|
*/
|
|
2321
2481
|
sessionGenerations = /* @__PURE__ */ new Map();
|
|
2482
|
+
pendingClears = /* @__PURE__ */ new Map();
|
|
2322
2483
|
/** Per-session active prompt tracking for dispatch modes. */
|
|
2323
2484
|
activePrompts = /* @__PURE__ */ new Map();
|
|
2324
2485
|
/** Per-session message buffer for collect mode. */
|
|
2325
2486
|
collectBuffers = /* @__PURE__ */ new Map();
|
|
2487
|
+
preflightedEnvelopes = /* @__PURE__ */ new WeakSet();
|
|
2326
2488
|
bridgeToolCallListener = /* @__PURE__ */ __name((event) => {
|
|
2327
2489
|
this.dispatchToolCall(event);
|
|
2328
2490
|
}, "bridgeToolCallListener");
|
|
2329
2491
|
bridgeSessionDiedListener = /* @__PURE__ */ __name((event) => {
|
|
2330
2492
|
this.onSessionDied(event.sessionId);
|
|
2331
2493
|
}, "bridgeSessionDiedListener");
|
|
2494
|
+
bridgePermissionRequestListener = /* @__PURE__ */ __name((event) => {
|
|
2495
|
+
void this.dispatchPermissionRequest(event).catch((err) => {
|
|
2496
|
+
process.stderr.write(`[${this.name}] permission relay failed for request ${sanitizeLogText(event.requestId, 128)}: ${this.lifecycleError(err)}
|
|
2497
|
+
`);
|
|
2498
|
+
});
|
|
2499
|
+
}, "bridgePermissionRequestListener");
|
|
2500
|
+
bridgePermissionResolvedListener = /* @__PURE__ */ __name((event) => {
|
|
2501
|
+
this.dispatchPermissionResolved(event);
|
|
2502
|
+
}, "bridgePermissionResolvedListener");
|
|
2503
|
+
pendingPermissions = /* @__PURE__ */ new Map();
|
|
2504
|
+
pendingPermissionsByChat = /* @__PURE__ */ new Map();
|
|
2332
2505
|
channelLoopToolHandler = {
|
|
2333
2506
|
canHandle: /* @__PURE__ */ __name((sessionId) => this.router.getTarget(sessionId)?.channelName === this.name, "canHandle"),
|
|
2334
2507
|
create: /* @__PURE__ */ __name((sessionId, input) => this.createLoopFromTool(sessionId, input), "create"),
|
|
@@ -2358,6 +2531,78 @@ var ChannelBase = class {
|
|
|
2358
2531
|
}
|
|
2359
2532
|
this.onToolCall(chatId, event);
|
|
2360
2533
|
}
|
|
2534
|
+
async dispatchPermissionRequest(event) {
|
|
2535
|
+
const target = this.permissionTargetForEvent(event);
|
|
2536
|
+
if (!target) {
|
|
2537
|
+
try {
|
|
2538
|
+
await this.bridge.respondToPermission?.(event.requestId, {
|
|
2539
|
+
outcome: { outcome: "cancelled" }
|
|
2540
|
+
});
|
|
2541
|
+
} catch (respondErr) {
|
|
2542
|
+
process.stderr.write(`[${this.name}] permission cancellation failed for request ${sanitizeLogText(event.requestId, 128)}: ${this.lifecycleError(respondErr)}
|
|
2543
|
+
`);
|
|
2544
|
+
}
|
|
2545
|
+
return;
|
|
2546
|
+
}
|
|
2547
|
+
this.removePendingPermission(event.requestId);
|
|
2548
|
+
const pending = {
|
|
2549
|
+
requestId: event.requestId,
|
|
2550
|
+
sessionId: event.sessionId,
|
|
2551
|
+
target,
|
|
2552
|
+
request: event.request
|
|
2553
|
+
};
|
|
2554
|
+
this.pendingPermissions.set(event.requestId, pending);
|
|
2555
|
+
const chatKey = this.permissionChatKey(target);
|
|
2556
|
+
const requestIds = this.pendingPermissionsByChat.get(chatKey) ?? [];
|
|
2557
|
+
requestIds.push(event.requestId);
|
|
2558
|
+
this.pendingPermissionsByChat.set(chatKey, requestIds);
|
|
2559
|
+
try {
|
|
2560
|
+
const text = this.formatPermissionRequest(pending);
|
|
2561
|
+
if (target.threadId !== void 0 && this.supportsProactiveSend() && this.supportsProactiveTarget(target)) {
|
|
2562
|
+
await this.pushProactive(target, text);
|
|
2563
|
+
} else {
|
|
2564
|
+
await this.sendMessage(target.chatId, text);
|
|
2565
|
+
}
|
|
2566
|
+
} catch (err) {
|
|
2567
|
+
this.removePendingPermission(event.requestId);
|
|
2568
|
+
try {
|
|
2569
|
+
await this.bridge.respondToPermission?.(event.requestId, {
|
|
2570
|
+
outcome: { outcome: "cancelled" }
|
|
2571
|
+
});
|
|
2572
|
+
} catch (respondErr) {
|
|
2573
|
+
process.stderr.write(`[${this.name}] permission cancellation failed for request ${sanitizeLogText(event.requestId, 128)}: ${this.lifecycleError(respondErr)}
|
|
2574
|
+
`);
|
|
2575
|
+
}
|
|
2576
|
+
throw err;
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
permissionTargetForEvent(event) {
|
|
2580
|
+
const routeTarget = this.router.getTarget(event.sessionId);
|
|
2581
|
+
if (!routeTarget || routeTarget.channelName !== this.name) {
|
|
2582
|
+
return void 0;
|
|
2583
|
+
}
|
|
2584
|
+
const active = this.activePrompts.get(event.sessionId);
|
|
2585
|
+
if (!active) {
|
|
2586
|
+
return routeTarget;
|
|
2587
|
+
}
|
|
2588
|
+
const target = {
|
|
2589
|
+
channelName: routeTarget.channelName,
|
|
2590
|
+
senderId: active.senderId ?? routeTarget.senderId,
|
|
2591
|
+
chatId: active.chatId
|
|
2592
|
+
};
|
|
2593
|
+
if (active.threadId !== void 0) {
|
|
2594
|
+
target.threadId = active.threadId;
|
|
2595
|
+
}
|
|
2596
|
+
if (active.isGroup !== void 0) {
|
|
2597
|
+
target.isGroup = active.isGroup;
|
|
2598
|
+
} else if (routeTarget.isGroup !== void 0) {
|
|
2599
|
+
target.isGroup = routeTarget.isGroup;
|
|
2600
|
+
}
|
|
2601
|
+
return target;
|
|
2602
|
+
}
|
|
2603
|
+
dispatchPermissionResolved(event) {
|
|
2604
|
+
this.removePendingPermission(event.requestId);
|
|
2605
|
+
}
|
|
2361
2606
|
constructor(name, config, bridge, options) {
|
|
2362
2607
|
this.name = name;
|
|
2363
2608
|
this.config = config;
|
|
@@ -2366,9 +2611,11 @@ var ChannelBase = class {
|
|
|
2366
2611
|
this.identity = Object.freeze(this.resolveIdentity(name, config));
|
|
2367
2612
|
this.memoryScope = Object.freeze(this.resolveMemoryScope(name, config));
|
|
2368
2613
|
this.channelMemory = options?.channelMemory;
|
|
2614
|
+
this.memoryIntentClassifier = options?.memoryIntentClassifier;
|
|
2369
2615
|
this.groupHistory = new GroupHistoryStore(options?.groupHistoryPath ?? join4(getGlobalQwenDir(), "channels", `${encodeURIComponent(name)}-group-history.jsonl`));
|
|
2370
2616
|
this.loopController = options?.loopController;
|
|
2371
2617
|
this.groupGate = new GroupGate(config.groupPolicy, config.groups);
|
|
2618
|
+
this.dmGate = new DmGate(config.dmPolicy);
|
|
2372
2619
|
const pairingStore = config.senderPolicy === "pairing" ? new PairingStore(name) : void 0;
|
|
2373
2620
|
this.gate = new SenderGate(config.senderPolicy, config.allowedUsers, pairingStore);
|
|
2374
2621
|
this.router = options?.router || new SessionRouter(bridge, config.cwd, config.sessionScope);
|
|
@@ -2488,6 +2735,7 @@ var ChannelBase = class {
|
|
|
2488
2735
|
if (this.registerBridgeEvents) {
|
|
2489
2736
|
this.detachBridgeEvents(this.bridge);
|
|
2490
2737
|
}
|
|
2738
|
+
this.clearPendingPermissions();
|
|
2491
2739
|
this.router.setBridge(bridge);
|
|
2492
2740
|
this.bridge = bridge;
|
|
2493
2741
|
if (this.loopController) {
|
|
@@ -2588,6 +2836,8 @@ ${promptText}`;
|
|
|
2588
2836
|
done,
|
|
2589
2837
|
resolve: doneResolve,
|
|
2590
2838
|
chatId: job.target.chatId,
|
|
2839
|
+
threadId: job.target.threadId,
|
|
2840
|
+
isGroup: job.target.isGroup,
|
|
2591
2841
|
messageId: job.id,
|
|
2592
2842
|
senderId: job.target.senderId,
|
|
2593
2843
|
senderName: job.createdBy,
|
|
@@ -2701,6 +2951,7 @@ ${promptText}`;
|
|
|
2701
2951
|
const lost = buffer.length;
|
|
2702
2952
|
const coalesced = buffer.map((b) => b.text).join("\n\n");
|
|
2703
2953
|
const lastEnvelope = buffer[buffer.length - 1].envelope;
|
|
2954
|
+
this.notifyPromptBufferDrained(lastEnvelope.chatId, sessionId, buffer);
|
|
2704
2955
|
const syntheticEnvelope = {
|
|
2705
2956
|
...lastEnvelope,
|
|
2706
2957
|
text: coalesced,
|
|
@@ -2710,7 +2961,8 @@ ${promptText}`;
|
|
|
2710
2961
|
imageBase64: void 0,
|
|
2711
2962
|
imageMimeType: void 0
|
|
2712
2963
|
};
|
|
2713
|
-
this.
|
|
2964
|
+
this.markPreflighted(syntheticEnvelope);
|
|
2965
|
+
this.processInbound(syntheticEnvelope).catch((err) => {
|
|
2714
2966
|
process.stderr.write(`[${this.name}] dropped ${lost} buffered message(s) after loop ${job.id} for session ${sessionId} (last sender ${lastEnvelope.senderId}): ${err instanceof Error ? err.message : String(err)}
|
|
2715
2967
|
`);
|
|
2716
2968
|
});
|
|
@@ -2800,11 +3052,39 @@ ${promptText}`;
|
|
|
2800
3052
|
}
|
|
2801
3053
|
active.cancelled = true;
|
|
2802
3054
|
this.stopActiveStreaming(active, sessionId, reason);
|
|
2803
|
-
this.
|
|
3055
|
+
this.dropCollectBuffer(sessionId);
|
|
2804
3056
|
this.emitTaskCancellation(active, sessionId, reason);
|
|
2805
3057
|
return true;
|
|
2806
3058
|
});
|
|
2807
3059
|
}
|
|
3060
|
+
dropCollectBuffer(sessionId) {
|
|
3061
|
+
const buffer = this.collectBuffers.get(sessionId);
|
|
3062
|
+
if (!buffer)
|
|
3063
|
+
return;
|
|
3064
|
+
this.collectBuffers.delete(sessionId);
|
|
3065
|
+
const chatId = buffer[0]?.envelope.chatId ?? "";
|
|
3066
|
+
const messageIds = this.collectBufferMessageIds(buffer);
|
|
3067
|
+
try {
|
|
3068
|
+
this.onPromptBufferDropped(chatId, sessionId, messageIds);
|
|
3069
|
+
} catch (err) {
|
|
3070
|
+
process.stderr.write(`[${this.name}] onPromptBufferDropped threw for session ${sessionId}: ${err instanceof Error ? err.message : err}
|
|
3071
|
+
`);
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
notifyPromptBufferDrained(chatId, sessionId, buffer) {
|
|
3075
|
+
const messageIds = this.collectBufferMessageIds(buffer);
|
|
3076
|
+
if (messageIds.length === 0)
|
|
3077
|
+
return;
|
|
3078
|
+
try {
|
|
3079
|
+
this.onPromptBufferDrained(chatId, sessionId, messageIds);
|
|
3080
|
+
} catch (err) {
|
|
3081
|
+
process.stderr.write(`[${this.name}] onPromptBufferDrained threw for session ${sessionId}: ${err instanceof Error ? err.message : err}
|
|
3082
|
+
`);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
collectBufferMessageIds(buffer) {
|
|
3086
|
+
return buffer.map((entry) => entry.envelope.messageId).filter((id) => typeof id === "string" && id.length > 0);
|
|
3087
|
+
}
|
|
2808
3088
|
logCancelSessionFailure(sessionId, err) {
|
|
2809
3089
|
process.stderr.write(`[${sanitizeLogText(this.name, 64)}] cancelSession failed for session=${sanitizeLogText(sessionId, 64)}: ${this.lifecycleError(err)}
|
|
2810
3090
|
`);
|
|
@@ -2834,14 +3114,19 @@ ${promptText}`;
|
|
|
2834
3114
|
onSessionDied(sessionId) {
|
|
2835
3115
|
this.router.removeSessionId(sessionId);
|
|
2836
3116
|
this.instructedSessions.delete(sessionId);
|
|
3117
|
+
this.removePendingPermissionsForSession(sessionId);
|
|
2837
3118
|
}
|
|
2838
3119
|
attachBridgeEvents(bridge) {
|
|
2839
3120
|
bridge.on("toolCall", this.bridgeToolCallListener);
|
|
2840
3121
|
bridge.on("sessionDied", this.bridgeSessionDiedListener);
|
|
3122
|
+
bridge.on("permissionRequest", this.bridgePermissionRequestListener);
|
|
3123
|
+
bridge.on("permissionResolved", this.bridgePermissionResolvedListener);
|
|
2841
3124
|
}
|
|
2842
3125
|
detachBridgeEvents(bridge) {
|
|
2843
3126
|
bridge.off("toolCall", this.bridgeToolCallListener);
|
|
2844
3127
|
bridge.off("sessionDied", this.bridgeSessionDiedListener);
|
|
3128
|
+
bridge.off("permissionRequest", this.bridgePermissionRequestListener);
|
|
3129
|
+
bridge.off("permissionResolved", this.bridgePermissionResolvedListener);
|
|
2845
3130
|
}
|
|
2846
3131
|
/**
|
|
2847
3132
|
* Called when a prompt actually begins processing (inside the session queue).
|
|
@@ -2850,6 +3135,12 @@ ${promptText}`;
|
|
|
2850
3135
|
*/
|
|
2851
3136
|
onPromptStart(_chatId, _sessionId, _messageId) {
|
|
2852
3137
|
}
|
|
3138
|
+
onPromptBuffered(_chatId, _sessionId, _messageId) {
|
|
3139
|
+
}
|
|
3140
|
+
onPromptBufferDrained(_chatId, _sessionId, _messageIds) {
|
|
3141
|
+
}
|
|
3142
|
+
onPromptBufferDropped(_chatId, _sessionId, _messageIds) {
|
|
3143
|
+
}
|
|
2853
3144
|
/**
|
|
2854
3145
|
* Called when a prompt finishes (response sent or cancelled).
|
|
2855
3146
|
* Override to hide the working indicator.
|
|
@@ -2900,6 +3191,182 @@ ${promptText}`;
|
|
|
2900
3191
|
return true;
|
|
2901
3192
|
});
|
|
2902
3193
|
}
|
|
3194
|
+
permissionChatKey(target) {
|
|
3195
|
+
return `${target.chatId}\0${target.threadId ?? ""}`;
|
|
3196
|
+
}
|
|
3197
|
+
pendingPermissionIdsForChatKey(chatKey) {
|
|
3198
|
+
const requestIds = this.pendingPermissionsByChat.get(chatKey);
|
|
3199
|
+
if (!requestIds) {
|
|
3200
|
+
return [];
|
|
3201
|
+
}
|
|
3202
|
+
const live = requestIds.filter((id) => this.pendingPermissions.has(id));
|
|
3203
|
+
if (live.length === 0) {
|
|
3204
|
+
this.pendingPermissionsByChat.delete(chatKey);
|
|
3205
|
+
} else if (live.length !== requestIds.length) {
|
|
3206
|
+
this.pendingPermissionsByChat.set(chatKey, live);
|
|
3207
|
+
}
|
|
3208
|
+
return live;
|
|
3209
|
+
}
|
|
3210
|
+
removePendingPermission(requestId) {
|
|
3211
|
+
const pending = this.pendingPermissions.get(requestId);
|
|
3212
|
+
if (!pending) {
|
|
3213
|
+
return;
|
|
3214
|
+
}
|
|
3215
|
+
this.pendingPermissions.delete(requestId);
|
|
3216
|
+
const chatKey = this.permissionChatKey(pending.target);
|
|
3217
|
+
const requestIds = this.pendingPermissionsByChat.get(chatKey);
|
|
3218
|
+
if (!requestIds) {
|
|
3219
|
+
return;
|
|
3220
|
+
}
|
|
3221
|
+
const remaining = requestIds.filter((id) => id !== requestId);
|
|
3222
|
+
if (remaining.length === 0) {
|
|
3223
|
+
this.pendingPermissionsByChat.delete(chatKey);
|
|
3224
|
+
} else {
|
|
3225
|
+
this.pendingPermissionsByChat.set(chatKey, remaining);
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
removePendingPermissionsForSession(sessionId) {
|
|
3229
|
+
const requestIds = Array.from(this.pendingPermissions).filter(([, pending]) => pending.sessionId === sessionId).map(([requestId]) => requestId);
|
|
3230
|
+
for (const requestId of requestIds) {
|
|
3231
|
+
this.removePendingPermission(requestId);
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
clearPendingPermissions() {
|
|
3235
|
+
this.pendingPermissions.clear();
|
|
3236
|
+
this.pendingPermissionsByChat.clear();
|
|
3237
|
+
}
|
|
3238
|
+
pendingPermissionForEnvelope(envelope, args) {
|
|
3239
|
+
const trimmed = args.trim();
|
|
3240
|
+
if (trimmed) {
|
|
3241
|
+
const explicit = this.pendingPermissions.get(trimmed);
|
|
3242
|
+
if (explicit && this.canEnvelopeAnswerPendingPermission(envelope, explicit)) {
|
|
3243
|
+
return { kind: "found", pending: explicit };
|
|
3244
|
+
}
|
|
3245
|
+
return { kind: "none", explicit: true };
|
|
3246
|
+
}
|
|
3247
|
+
const requestIds = this.pendingPermissionIdsForChatKey(this.permissionChatKey(envelope));
|
|
3248
|
+
if (requestIds.length === 0) {
|
|
3249
|
+
return { kind: "none", explicit: false };
|
|
3250
|
+
}
|
|
3251
|
+
const matching = requestIds.map((id) => this.pendingPermissions.get(id)).filter((pending) => pending !== void 0 && this.canEnvelopeAnswerPendingPermission(envelope, pending));
|
|
3252
|
+
if (matching.length === 0) {
|
|
3253
|
+
return { kind: "none", explicit: false };
|
|
3254
|
+
}
|
|
3255
|
+
if (matching.length > 1) {
|
|
3256
|
+
return {
|
|
3257
|
+
kind: "ambiguous",
|
|
3258
|
+
requestIds: matching.map((pending) => pending.requestId)
|
|
3259
|
+
};
|
|
3260
|
+
}
|
|
3261
|
+
return { kind: "found", pending: matching[0] };
|
|
3262
|
+
}
|
|
3263
|
+
canEnvelopeAnswerPendingPermission(envelope, pending) {
|
|
3264
|
+
return pending.target.chatId === envelope.chatId && pending.target.threadId === envelope.threadId && (this.isSharedSessionTarget(pending.target) || pending.target.senderId === envelope.senderId);
|
|
3265
|
+
}
|
|
3266
|
+
formatPermissionRequest(pending) {
|
|
3267
|
+
const { toolCall } = pending.request;
|
|
3268
|
+
const title = sanitizeQuotedText(toolCall.title || "Tool use", 160);
|
|
3269
|
+
const alwaysOption = this.approvalAlwaysOption(pending);
|
|
3270
|
+
const replies = [
|
|
3271
|
+
"/approve allow once",
|
|
3272
|
+
...alwaysOption ? [`/approve-always ${alwaysOption.label}`] : [],
|
|
3273
|
+
"/deny deny"
|
|
3274
|
+
];
|
|
3275
|
+
const lines = [
|
|
3276
|
+
"Permission required to run a tool",
|
|
3277
|
+
"",
|
|
3278
|
+
"Command:",
|
|
3279
|
+
title,
|
|
3280
|
+
"",
|
|
3281
|
+
"Reply with:",
|
|
3282
|
+
...replies
|
|
3283
|
+
];
|
|
3284
|
+
return lines.join("\n");
|
|
3285
|
+
}
|
|
3286
|
+
approvalOptionId(pending) {
|
|
3287
|
+
const options = pending.request.options;
|
|
3288
|
+
return options.find((option) => option.kind === "allow_once")?.optionId ?? options.find((option) => option.optionId === "proceed_once" && option.kind === void 0)?.optionId;
|
|
3289
|
+
}
|
|
3290
|
+
approvalAlwaysOption(pending) {
|
|
3291
|
+
const options = pending.request.options.filter((option2) => option2.kind === "allow_always");
|
|
3292
|
+
const option = this.findScopedAlwaysOption(options, "project") ?? this.findScopedAlwaysOption(options, "user") ?? options[0];
|
|
3293
|
+
if (!option) {
|
|
3294
|
+
return void 0;
|
|
3295
|
+
}
|
|
3296
|
+
return {
|
|
3297
|
+
optionId: option.optionId,
|
|
3298
|
+
label: this.approvalAlwaysLabel(option)
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
findScopedAlwaysOption(options, scope) {
|
|
3302
|
+
return options.find((option) => option.optionId === `proceed_always_${scope}`);
|
|
3303
|
+
}
|
|
3304
|
+
approvalAlwaysLabel(option) {
|
|
3305
|
+
if (option.optionId === "proceed_always_project") {
|
|
3306
|
+
return "always allow for this project";
|
|
3307
|
+
}
|
|
3308
|
+
if (option.optionId === "proceed_always_user") {
|
|
3309
|
+
return "always allow for this user";
|
|
3310
|
+
}
|
|
3311
|
+
return "always allow";
|
|
3312
|
+
}
|
|
3313
|
+
denialResponse(pending) {
|
|
3314
|
+
const option = pending.request.options.find((candidate) => candidate.kind === "reject_once") ?? pending.request.options.find((candidate) => candidate.optionId === "cancel" && candidate.kind === void 0);
|
|
3315
|
+
if (option) {
|
|
3316
|
+
return { outcome: { outcome: "selected", optionId: option.optionId } };
|
|
3317
|
+
}
|
|
3318
|
+
return { outcome: { outcome: "cancelled" } };
|
|
3319
|
+
}
|
|
3320
|
+
async handlePermissionResponseCommand(envelope, args, decision) {
|
|
3321
|
+
if (!this.isAuthorizedForSharedSession(envelope)) {
|
|
3322
|
+
await this.sendMessage(envelope.chatId, "Only authorized members can answer permission requests in this shared session.");
|
|
3323
|
+
return true;
|
|
3324
|
+
}
|
|
3325
|
+
const lookup = this.pendingPermissionForEnvelope(envelope, args);
|
|
3326
|
+
if (lookup.kind === "ambiguous") {
|
|
3327
|
+
const requestList = lookup.requestIds.slice(0, 6).map((id) => {
|
|
3328
|
+
const pending2 = this.pendingPermissions.get(id);
|
|
3329
|
+
const title = pending2 ? `: ${sanitizeQuotedText(pending2.request.toolCall.title || "Tool use", 160)}` : "";
|
|
3330
|
+
return `- ${sanitizeQuotedText(id, 128)}${title}`;
|
|
3331
|
+
}).join("\n");
|
|
3332
|
+
await this.sendMessage(envelope.chatId, `Multiple permission requests are pending for this chat. Reply with /${decision} <request-id>.
|
|
3333
|
+
${requestList}`);
|
|
3334
|
+
return true;
|
|
3335
|
+
}
|
|
3336
|
+
if (lookup.kind === "none") {
|
|
3337
|
+
await this.sendMessage(envelope.chatId, lookup.explicit ? "No pending permission request with that id for this chat." : "No pending permission request for this chat.");
|
|
3338
|
+
return true;
|
|
3339
|
+
}
|
|
3340
|
+
if (!this.bridge.respondToPermission) {
|
|
3341
|
+
await this.sendMessage(envelope.chatId, "Permission relay is not available for this session.");
|
|
3342
|
+
return true;
|
|
3343
|
+
}
|
|
3344
|
+
const { pending } = lookup;
|
|
3345
|
+
const response = (() => {
|
|
3346
|
+
if (decision === "deny") {
|
|
3347
|
+
return this.denialResponse(pending);
|
|
3348
|
+
}
|
|
3349
|
+
const optionId = decision === "approve" ? this.approvalOptionId(pending) : this.approvalAlwaysOption(pending)?.optionId;
|
|
3350
|
+
return optionId ? { outcome: { outcome: "selected", optionId } } : void 0;
|
|
3351
|
+
})();
|
|
3352
|
+
if (!response) {
|
|
3353
|
+
await this.sendMessage(envelope.chatId, decision === "approve-always" ? "This permission request has no always-allow option." : "This permission request has no approvable option.");
|
|
3354
|
+
return true;
|
|
3355
|
+
}
|
|
3356
|
+
let accepted;
|
|
3357
|
+
try {
|
|
3358
|
+
accepted = await this.bridge.respondToPermission(pending.requestId, response);
|
|
3359
|
+
} catch (err) {
|
|
3360
|
+
this.removePendingPermission(pending.requestId);
|
|
3361
|
+
process.stderr.write(`[${this.name}] permission response failed for request ${sanitizeLogText(pending.requestId, 128)}: ${this.lifecycleError(err)}
|
|
3362
|
+
`);
|
|
3363
|
+
await this.sendMessage(envelope.chatId, "Failed to answer the permission request.");
|
|
3364
|
+
return true;
|
|
3365
|
+
}
|
|
3366
|
+
this.removePendingPermission(pending.requestId);
|
|
3367
|
+
await this.sendMessage(envelope.chatId, accepted ? decision === "approve" ? "Permission approved." : decision === "approve-always" ? "Permission approved always." : "Permission denied." : "Permission request is no longer pending.");
|
|
3368
|
+
return true;
|
|
3369
|
+
}
|
|
2903
3370
|
/** Register shared slash commands. Called from constructor. */
|
|
2904
3371
|
registerSharedCommands() {
|
|
2905
3372
|
const doClear = /* @__PURE__ */ __name(async (envelope) => {
|
|
@@ -2913,8 +3380,9 @@ ${promptText}`;
|
|
|
2913
3380
|
`);
|
|
2914
3381
|
}
|
|
2915
3382
|
this.sessionGenerations.set(id, (this.sessionGenerations.get(id) ?? 0) + 1);
|
|
3383
|
+
this.removePendingPermissionsForSession(id);
|
|
2916
3384
|
const active = this.activePrompts.get(id);
|
|
2917
|
-
this.
|
|
3385
|
+
this.dropCollectBuffer(id);
|
|
2918
3386
|
if (active) {
|
|
2919
3387
|
const settled = await this.cancelAndAwaitActive(active, id);
|
|
2920
3388
|
if (!settled) {
|
|
@@ -2966,77 +3434,23 @@ ${promptText}`;
|
|
|
2966
3434
|
this.registerCommand("clear", clearHandler);
|
|
2967
3435
|
this.registerCommand("reset", clearHandler);
|
|
2968
3436
|
this.registerCommand("new", clearHandler);
|
|
2969
|
-
this.registerCommand("
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
return true;
|
|
2973
|
-
}
|
|
2974
|
-
const active = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
|
|
2975
|
-
const scopeNote = this.config.sessionScope === "single" ? " (shared channel-wide)" : this.isSharedSession(envelope) ? envelope.isGroup ? " (shared by this group)" : "" : envelope.isGroup ? " (private to you)" : "";
|
|
2976
|
-
await this.sendMessage(envelope.chatId, [
|
|
2977
|
-
`Channel: ${this.name}`,
|
|
2978
|
-
// Identity/memory lines only for channels that opted in — keep
|
|
2979
|
-
// unconfigured channels' output unchanged.
|
|
2980
|
-
...this.shouldPrependChannelBoundaryPrompt() ? [
|
|
2981
|
-
`Identity: ${sanitizeQuotedText(this.identity.displayName, 128)}`,
|
|
2982
|
-
`Memory: ${sanitizeQuotedText(this.memoryScope.namespace, 128)}`
|
|
2983
|
-
] : [],
|
|
2984
|
-
// Only the basename — don't leak the absolute cwd to group members.
|
|
2985
|
-
`Workspace: ${basename(this.config.cwd)}`,
|
|
2986
|
-
`Session: ${active ? "active" : "none"}${scopeNote}`
|
|
2987
|
-
].join("\n"));
|
|
2988
|
-
return true;
|
|
2989
|
-
});
|
|
3437
|
+
this.registerCommand("approve", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve"));
|
|
3438
|
+
this.registerCommand("approve-always", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve-always"));
|
|
3439
|
+
this.registerCommand("deny", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "deny"));
|
|
2990
3440
|
this.registerCommand("remember-channel", async (envelope, args) => {
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
}
|
|
2994
|
-
if (envelope.isGroup) {
|
|
2995
|
-
await this.sendMessage(envelope.chatId, "Channel memory cannot be changed in group chats.");
|
|
2996
|
-
return true;
|
|
2997
|
-
}
|
|
2998
|
-
if (args.trim() === "") {
|
|
3441
|
+
const text = args.trim();
|
|
3442
|
+
if (text === "") {
|
|
2999
3443
|
await this.sendMessage(envelope.chatId, "Usage: /remember-channel <text>");
|
|
3000
3444
|
return true;
|
|
3001
3445
|
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
}
|
|
3006
|
-
try {
|
|
3007
|
-
await channelMemory.appendChannelMemory(this.channelMemoryTarget(envelope), args.trim());
|
|
3008
|
-
} catch (error) {
|
|
3009
|
-
const message = this.channelMemoryErrorMessage(error);
|
|
3010
|
-
this.logChannelMemoryError("save", envelope, message);
|
|
3011
|
-
await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
3012
|
-
return true;
|
|
3013
|
-
}
|
|
3014
|
-
this.invalidateSessionContext(envelope);
|
|
3015
|
-
await this.sendMessage(envelope.chatId, "Channel memory updated.");
|
|
3446
|
+
await this.handleChannelMemoryIntent(envelope, {
|
|
3447
|
+
kind: "remember",
|
|
3448
|
+
text
|
|
3449
|
+
});
|
|
3016
3450
|
return true;
|
|
3017
3451
|
});
|
|
3018
3452
|
this.registerCommand("channel-memory", async (envelope) => {
|
|
3019
|
-
|
|
3020
|
-
return true;
|
|
3021
|
-
}
|
|
3022
|
-
if (envelope.isGroup) {
|
|
3023
|
-
await this.sendMessage(envelope.chatId, "Channel memory cannot be shown in group chats.");
|
|
3024
|
-
return true;
|
|
3025
|
-
}
|
|
3026
|
-
const channelMemory = await this.getChannelMemory(envelope);
|
|
3027
|
-
if (!channelMemory) {
|
|
3028
|
-
return true;
|
|
3029
|
-
}
|
|
3030
|
-
let text;
|
|
3031
|
-
try {
|
|
3032
|
-
text = (await channelMemory.readChannelMemory(this.channelMemoryTarget(envelope))).trim();
|
|
3033
|
-
} catch (error) {
|
|
3034
|
-
const message = this.channelMemoryErrorMessage(error);
|
|
3035
|
-
this.logChannelMemoryError("read", envelope, message);
|
|
3036
|
-
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
3037
|
-
return true;
|
|
3038
|
-
}
|
|
3039
|
-
await this.sendMessage(envelope.chatId, text === "" ? "No channel memory saved." : sanitizePromptText(text));
|
|
3453
|
+
await this.handleChannelMemoryIntent(envelope, { kind: "list" });
|
|
3040
3454
|
return true;
|
|
3041
3455
|
});
|
|
3042
3456
|
this.registerCommand("forget-channel", async (envelope, args) => {
|
|
@@ -3051,21 +3465,28 @@ ${promptText}`;
|
|
|
3051
3465
|
await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Re-send with "confirm" (e.g. /forget-channel confirm) to proceed.');
|
|
3052
3466
|
return true;
|
|
3053
3467
|
}
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
result = await channelMemory.clearChannelMemory(this.channelMemoryTarget(envelope));
|
|
3061
|
-
} catch (error) {
|
|
3062
|
-
const message = this.channelMemoryErrorMessage(error);
|
|
3063
|
-
this.logChannelMemoryError("clear", envelope, message);
|
|
3064
|
-
await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
3468
|
+
await this.handleChannelMemoryIntent(envelope, { kind: "clear_confirm" }, { skipPendingClear: true });
|
|
3469
|
+
return true;
|
|
3470
|
+
});
|
|
3471
|
+
this.registerCommand("who", async (envelope) => {
|
|
3472
|
+
if (!this.isAuthorizedForSharedSession(envelope)) {
|
|
3473
|
+
await this.sendMessage(envelope.chatId, "Only authorized members can view this shared session.");
|
|
3065
3474
|
return true;
|
|
3066
3475
|
}
|
|
3067
|
-
this.
|
|
3068
|
-
|
|
3476
|
+
const active = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
|
|
3477
|
+
const scopeNote = this.config.sessionScope === "single" ? " (shared channel-wide)" : this.isSharedSession(envelope) ? envelope.isGroup ? " (shared by this group)" : "" : envelope.isGroup ? " (private to you)" : "";
|
|
3478
|
+
await this.sendMessage(envelope.chatId, [
|
|
3479
|
+
`Channel: ${this.name}`,
|
|
3480
|
+
// Identity/memory lines only for channels that opted in — keep
|
|
3481
|
+
// unconfigured channels' output unchanged.
|
|
3482
|
+
...this.shouldPrependChannelBoundaryPrompt() ? [
|
|
3483
|
+
`Identity: ${sanitizeQuotedText(this.identity.displayName, 128)}`,
|
|
3484
|
+
`Memory: ${sanitizeQuotedText(this.memoryScope.namespace, 128)}`
|
|
3485
|
+
] : [],
|
|
3486
|
+
// Only the basename — don't leak the absolute cwd to group members.
|
|
3487
|
+
`Workspace: ${basename(this.config.cwd)}`,
|
|
3488
|
+
`Session: ${active ? "active" : "none"}${scopeNote}`
|
|
3489
|
+
].join("\n"));
|
|
3069
3490
|
return true;
|
|
3070
3491
|
});
|
|
3071
3492
|
this.registerCommand("help", async (envelope) => {
|
|
@@ -3075,20 +3496,23 @@ ${promptText}`;
|
|
|
3075
3496
|
this.isSharedSession(envelope) ? "/clear confirm \u2014 Clear the shared session (aliases: /reset, /new)" : "/clear \u2014 Clear your session (aliases: /reset, /new)",
|
|
3076
3497
|
"/who \u2014 Show current session & workspace",
|
|
3077
3498
|
"/status \u2014 Show session info",
|
|
3078
|
-
"/
|
|
3079
|
-
"/
|
|
3080
|
-
"/
|
|
3499
|
+
"/approve [request-id] \u2014 Approve a pending permission request",
|
|
3500
|
+
"/approve-always [request-id] \u2014 Always approve a pending permission request",
|
|
3501
|
+
"/deny [request-id] \u2014 Deny a pending permission request"
|
|
3081
3502
|
];
|
|
3082
3503
|
const sharedCmds = /* @__PURE__ */ new Set([
|
|
3083
3504
|
"help",
|
|
3084
3505
|
"clear",
|
|
3085
3506
|
"reset",
|
|
3086
3507
|
"new",
|
|
3087
|
-
"
|
|
3088
|
-
"
|
|
3508
|
+
"approve",
|
|
3509
|
+
"approve-always",
|
|
3510
|
+
"deny",
|
|
3089
3511
|
"remember-channel",
|
|
3090
3512
|
"channel-memory",
|
|
3091
|
-
"forget-channel"
|
|
3513
|
+
"forget-channel",
|
|
3514
|
+
"who",
|
|
3515
|
+
"status"
|
|
3092
3516
|
]);
|
|
3093
3517
|
const platformCmds = [...this.commands.keys()].filter((c) => !sharedCmds.has(c));
|
|
3094
3518
|
if (platformCmds.length > 0) {
|
|
@@ -3433,7 +3857,7 @@ ${promptText}`;
|
|
|
3433
3857
|
isMentioned: true,
|
|
3434
3858
|
isReplyToBot: true
|
|
3435
3859
|
};
|
|
3436
|
-
return this.groupGate.check(envelope).allowed && this.gate.isAllowed(normalizedTarget.senderId) && this.isAuthorizedForSharedSession(envelope);
|
|
3860
|
+
return this.groupGate.check(envelope).allowed && this.dmGate.check(envelope).allowed && this.gate.isAllowed(normalizedTarget.senderId) && this.isAuthorizedForSharedSession(envelope);
|
|
3437
3861
|
}
|
|
3438
3862
|
/** Check if a message text matches a registered local command. */
|
|
3439
3863
|
isLocalCommand(text) {
|
|
@@ -3486,6 +3910,118 @@ ${promptText}`;
|
|
|
3486
3910
|
}
|
|
3487
3911
|
return this.channelMemory;
|
|
3488
3912
|
}
|
|
3913
|
+
async handleChannelMemoryIntent(envelope, intent, options = {}) {
|
|
3914
|
+
if (!await this.ensureChannelMemoryAuthorized(envelope)) {
|
|
3915
|
+
return;
|
|
3916
|
+
}
|
|
3917
|
+
if (envelope.isGroup && intent.kind !== "list") {
|
|
3918
|
+
await this.sendMessage(envelope.chatId, "Channel memory cannot be changed in group chats.");
|
|
3919
|
+
return;
|
|
3920
|
+
}
|
|
3921
|
+
if (intent.kind === "clear_request") {
|
|
3922
|
+
this.setPendingClear(this.clearPendingKey(envelope));
|
|
3923
|
+
await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Say "\u786E\u8BA4\u6E05\u7A7A\u8BB0\u5FC6" or "confirm clear memory" to proceed.');
|
|
3924
|
+
return;
|
|
3925
|
+
}
|
|
3926
|
+
const channelMemory = await this.getChannelMemory(envelope);
|
|
3927
|
+
if (!channelMemory) {
|
|
3928
|
+
return;
|
|
3929
|
+
}
|
|
3930
|
+
if (intent.kind === "remember") {
|
|
3931
|
+
try {
|
|
3932
|
+
await channelMemory.appendChannelMemory(this.channelMemoryTarget(envelope), intent.text);
|
|
3933
|
+
} catch (error) {
|
|
3934
|
+
const message = this.channelMemoryErrorMessage(error);
|
|
3935
|
+
this.logChannelMemoryError("save", envelope, message);
|
|
3936
|
+
await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
3937
|
+
return;
|
|
3938
|
+
}
|
|
3939
|
+
this.invalidateSessionContext(envelope);
|
|
3940
|
+
await this.sendMessage(envelope.chatId, "Channel memory updated.");
|
|
3941
|
+
return;
|
|
3942
|
+
}
|
|
3943
|
+
if (intent.kind === "list") {
|
|
3944
|
+
let text;
|
|
3945
|
+
try {
|
|
3946
|
+
text = (await channelMemory.readChannelMemory(this.channelMemoryTarget(envelope))).trim();
|
|
3947
|
+
} catch (error) {
|
|
3948
|
+
const message = this.channelMemoryErrorMessage(error);
|
|
3949
|
+
this.logChannelMemoryError("read", envelope, message);
|
|
3950
|
+
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
3951
|
+
return;
|
|
3952
|
+
}
|
|
3953
|
+
await this.sendMessage(envelope.chatId, text === "" ? "No channel memory saved." : sanitizePromptText(text));
|
|
3954
|
+
return;
|
|
3955
|
+
}
|
|
3956
|
+
if (intent.kind === "clear_confirm") {
|
|
3957
|
+
if (!options.skipPendingClear) {
|
|
3958
|
+
const pendingKey = this.clearPendingKey(envelope);
|
|
3959
|
+
const expiresAt = this.pendingClears.get(pendingKey);
|
|
3960
|
+
this.pendingClears.delete(pendingKey);
|
|
3961
|
+
if (expiresAt === void 0 || expiresAt < Date.now()) {
|
|
3962
|
+
await this.sendMessage(envelope.chatId, 'No pending clear request. Say "\u6E05\u7A7A\u8BB0\u5FC6" first.');
|
|
3963
|
+
return;
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
let result;
|
|
3967
|
+
try {
|
|
3968
|
+
result = await channelMemory.clearChannelMemory(this.channelMemoryTarget(envelope));
|
|
3969
|
+
} catch (error) {
|
|
3970
|
+
const message = this.channelMemoryErrorMessage(error);
|
|
3971
|
+
this.logChannelMemoryError("clear", envelope, message);
|
|
3972
|
+
await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
3973
|
+
return;
|
|
3974
|
+
}
|
|
3975
|
+
this.invalidateSessionContext(envelope);
|
|
3976
|
+
await this.sendMessage(envelope.chatId, result.changed ? "Channel memory cleared." : "No channel memory saved.");
|
|
3977
|
+
return;
|
|
3978
|
+
}
|
|
3979
|
+
const unhandled = intent;
|
|
3980
|
+
throw new Error(`Unhandled channel memory intent: ${JSON.stringify(unhandled)}`);
|
|
3981
|
+
}
|
|
3982
|
+
shouldClassifyChannelMemoryIntent(text) {
|
|
3983
|
+
const normalized = text.replace(PROMPT_UNSAFE_INVISIBLES, "").trim();
|
|
3984
|
+
return this.channelMemory !== void 0 && this.memoryIntentClassifier !== void 0 && !normalized.startsWith("/") && CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE.test(normalized);
|
|
3985
|
+
}
|
|
3986
|
+
clearPendingKey(envelope) {
|
|
3987
|
+
return `${this.name}:${envelope.chatId}:${envelope.threadId ?? ""}:${envelope.senderId ?? ""}`;
|
|
3988
|
+
}
|
|
3989
|
+
setPendingClear(key) {
|
|
3990
|
+
const now = Date.now();
|
|
3991
|
+
for (const [pendingKey, expiresAt] of this.pendingClears) {
|
|
3992
|
+
if (expiresAt < now) {
|
|
3993
|
+
this.pendingClears.delete(pendingKey);
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3996
|
+
this.pendingClears.set(key, now + 6e4);
|
|
3997
|
+
}
|
|
3998
|
+
async classifyChannelMemoryIntent(text) {
|
|
3999
|
+
if (!this.memoryIntentClassifier) {
|
|
4000
|
+
return null;
|
|
4001
|
+
}
|
|
4002
|
+
let classified;
|
|
4003
|
+
try {
|
|
4004
|
+
classified = await this.memoryIntentClassifier.classifyChannelMemoryIntent(text);
|
|
4005
|
+
} catch (error) {
|
|
4006
|
+
process.stderr.write(`[${this.name}] channel memory intent classifier failed: ${sanitizeLogText(this.channelMemoryErrorMessage(error), 200)}
|
|
4007
|
+
`);
|
|
4008
|
+
return null;
|
|
4009
|
+
}
|
|
4010
|
+
if (classified.confidence < CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE) {
|
|
4011
|
+
return null;
|
|
4012
|
+
}
|
|
4013
|
+
if (classified.intent === "remember") {
|
|
4014
|
+
const memory = classified.memory?.trim();
|
|
4015
|
+
return memory ? { kind: "remember", text: memory } : null;
|
|
4016
|
+
}
|
|
4017
|
+
if (classified.intent === "list") {
|
|
4018
|
+
return { kind: "list" };
|
|
4019
|
+
}
|
|
4020
|
+
if (classified.intent === "clear_all") {
|
|
4021
|
+
return { kind: "clear_request" };
|
|
4022
|
+
}
|
|
4023
|
+
return null;
|
|
4024
|
+
}
|
|
3489
4025
|
channelMemoryErrorMessage(error) {
|
|
3490
4026
|
return error instanceof Error ? error.message : String(error);
|
|
3491
4027
|
}
|
|
@@ -3746,19 +4282,58 @@ ${formatted.join("\n")}
|
|
|
3746
4282
|
${CURRENT_MESSAGE_MARKER}
|
|
3747
4283
|
${promptText}`;
|
|
3748
4284
|
}
|
|
3749
|
-
|
|
4285
|
+
preflightInbound(envelope) {
|
|
3750
4286
|
const groupResult = this.groupGate.check(envelope);
|
|
3751
4287
|
if (!groupResult.allowed) {
|
|
3752
4288
|
if (groupResult.reason === "mention_required") {
|
|
3753
4289
|
this.recordPendingGroupHistory(envelope);
|
|
3754
4290
|
}
|
|
3755
|
-
return;
|
|
4291
|
+
return false;
|
|
4292
|
+
}
|
|
4293
|
+
const dmResult = this.dmGate.check(envelope);
|
|
4294
|
+
if (!dmResult.allowed) {
|
|
4295
|
+
return false;
|
|
3756
4296
|
}
|
|
3757
4297
|
const result = this.gate.check(envelope.senderId, envelope.senderName);
|
|
3758
4298
|
if (!result.allowed) {
|
|
3759
4299
|
if (result.pairingCode !== void 0) {
|
|
3760
|
-
|
|
4300
|
+
return this.onPairingRequired(envelope.chatId, result.pairingCode).then(() => false).catch((err) => {
|
|
4301
|
+
process.stderr.write(`[Channel:${this.name}] pairing notification failed: ${sanitizeLogText(err instanceof Error ? err.message : String(err), 200)}
|
|
4302
|
+
`);
|
|
4303
|
+
return false;
|
|
4304
|
+
});
|
|
3761
4305
|
}
|
|
4306
|
+
return false;
|
|
4307
|
+
}
|
|
4308
|
+
this.markPreflighted(envelope);
|
|
4309
|
+
return true;
|
|
4310
|
+
}
|
|
4311
|
+
async handleInbound(envelope) {
|
|
4312
|
+
const preflight = this.preflightInbound(envelope);
|
|
4313
|
+
if (!(isPromiseLike(preflight) ? await preflight : preflight))
|
|
4314
|
+
return;
|
|
4315
|
+
await this.processInbound(envelope);
|
|
4316
|
+
}
|
|
4317
|
+
markPreflighted(envelope) {
|
|
4318
|
+
this.preflightedEnvelopes.add(envelope);
|
|
4319
|
+
}
|
|
4320
|
+
/**
|
|
4321
|
+
* Process an inbound message after preflight gates have passed.
|
|
4322
|
+
*
|
|
4323
|
+
* This method does not run group gating, sender allowlisting, or pairing
|
|
4324
|
+
* checks. Callers must run preflightInbound() first unless the envelope was
|
|
4325
|
+
* already preflighted, such as during collect-buffer drain.
|
|
4326
|
+
*/
|
|
4327
|
+
async processInbound(envelope) {
|
|
4328
|
+
if (!this.preflightedEnvelopes.delete(envelope)) {
|
|
4329
|
+
throw new Error("processInbound called without a successful preflightInbound check.");
|
|
4330
|
+
}
|
|
4331
|
+
let memoryIntent = parseChannelMemoryIntent(envelope.text);
|
|
4332
|
+
if (!memoryIntent && this.shouldClassifyChannelMemoryIntent(envelope.text)) {
|
|
4333
|
+
memoryIntent = await this.classifyChannelMemoryIntent(envelope.text);
|
|
4334
|
+
}
|
|
4335
|
+
if (memoryIntent) {
|
|
4336
|
+
await this.handleChannelMemoryIntent(envelope, memoryIntent);
|
|
3762
4337
|
return;
|
|
3763
4338
|
}
|
|
3764
4339
|
const parsed = this.parseCommand(envelope.text);
|
|
@@ -3792,14 +4367,14 @@ ${promptText}`;
|
|
|
3792
4367
|
const bridgeShellCommand = this.bridge.shellCommand;
|
|
3793
4368
|
if (cmd && bridgeShellCommand) {
|
|
3794
4369
|
try {
|
|
3795
|
-
const
|
|
3796
|
-
const longestRun = Math.max(0, ...Array.from((
|
|
4370
|
+
const result = await bridgeShellCommand(sessionId, cmd);
|
|
4371
|
+
const longestRun = Math.max(0, ...Array.from((result.output || "").matchAll(/`+/g), (m) => m[0].length));
|
|
3797
4372
|
const fence = "`".repeat(Math.max(3, longestRun + 1));
|
|
3798
|
-
const output =
|
|
3799
|
-
${
|
|
4373
|
+
const output = result.output ? `${fence}
|
|
4374
|
+
${result.output}
|
|
3800
4375
|
${fence}` : "(no output)";
|
|
3801
|
-
const exitLine =
|
|
3802
|
-
Exit code: ${
|
|
4376
|
+
const exitLine = result.exitCode !== null && result.exitCode !== 0 ? `
|
|
4377
|
+
Exit code: ${result.exitCode}` : "";
|
|
3803
4378
|
await this.sendMessage(envelope.chatId, `$ ${cmd}
|
|
3804
4379
|
${output}${exitLine}`);
|
|
3805
4380
|
} catch (error) {
|
|
@@ -3852,6 +4427,12 @@ ${promptText}`;
|
|
|
3852
4427
|
this.collectBuffers.set(sessionId, buffer);
|
|
3853
4428
|
}
|
|
3854
4429
|
buffer.push({ text: promptText, envelope });
|
|
4430
|
+
try {
|
|
4431
|
+
this.onPromptBuffered(envelope.chatId, sessionId, envelope.messageId);
|
|
4432
|
+
} catch (err) {
|
|
4433
|
+
process.stderr.write(`[${this.name}] onPromptBuffered threw for session ${sessionId}: ${err instanceof Error ? err.message : err}
|
|
4434
|
+
`);
|
|
4435
|
+
}
|
|
3855
4436
|
return;
|
|
3856
4437
|
}
|
|
3857
4438
|
case "steer": {
|
|
@@ -3951,6 +4532,8 @@ ${promptToSend}`;
|
|
|
3951
4532
|
done,
|
|
3952
4533
|
resolve: doneResolve,
|
|
3953
4534
|
chatId: envelope.chatId,
|
|
4535
|
+
threadId: envelope.threadId,
|
|
4536
|
+
isGroup: envelope.isGroup,
|
|
3954
4537
|
messageId: envelope.messageId,
|
|
3955
4538
|
senderId: envelope.senderId,
|
|
3956
4539
|
senderName: envelope.senderName
|
|
@@ -4064,6 +4647,7 @@ ${promptToSend}`;
|
|
|
4064
4647
|
const lost = buffer.length;
|
|
4065
4648
|
const coalesced = buffer.map((b) => b.text).join("\n\n");
|
|
4066
4649
|
const lastEnvelope = buffer[buffer.length - 1].envelope;
|
|
4650
|
+
this.notifyPromptBufferDrained(lastEnvelope.chatId, sessionId, buffer);
|
|
4067
4651
|
const syntheticEnvelope = {
|
|
4068
4652
|
...lastEnvelope,
|
|
4069
4653
|
text: coalesced,
|
|
@@ -4075,7 +4659,8 @@ ${promptToSend}`;
|
|
|
4075
4659
|
imageBase64: void 0,
|
|
4076
4660
|
imageMimeType: void 0
|
|
4077
4661
|
};
|
|
4078
|
-
this.
|
|
4662
|
+
this.markPreflighted(syntheticEnvelope);
|
|
4663
|
+
this.processInbound(syntheticEnvelope).catch((err) => {
|
|
4079
4664
|
process.stderr.write(`[${this.name}] dropped ${lost} buffered message(s) on collect re-entry for session ${sessionId} (last sender ${lastEnvelope.senderId}): ${err instanceof Error ? err.message : String(err)}
|
|
4080
4665
|
`);
|
|
4081
4666
|
});
|
|
@@ -4101,6 +4686,10 @@ function truncateGroupHistoryField(value) {
|
|
|
4101
4686
|
return value.slice(0, GROUP_HISTORY_ENTRY_METADATA_LIMIT);
|
|
4102
4687
|
}
|
|
4103
4688
|
__name(truncateGroupHistoryField, "truncateGroupHistoryField");
|
|
4689
|
+
function isPromiseLike(value) {
|
|
4690
|
+
return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
4691
|
+
}
|
|
4692
|
+
__name(isPromiseLike, "isPromiseLike");
|
|
4104
4693
|
function truncateLoopLabel(prompt) {
|
|
4105
4694
|
const chars = Array.from(prompt);
|
|
4106
4695
|
return chars.length > 60 ? `${chars.slice(0, 57).join("")}...` : prompt;
|