@qwen-code/qwen-code 0.23.1-preview.1 → 0.23.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/bundled/computer-use/SKILL.md +189 -116
- package/bundled/goal-draft/SKILL.md +23 -13
- package/bundled/qc-helper/docs/_meta.ts +1 -0
- package/bundled/qc-helper/docs/configuration/model-providers.md +47 -1
- package/bundled/qc-helper/docs/configuration/settings.md +57 -7
- package/bundled/qc-helper/docs/conversations-recovery.md +102 -0
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +26 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +1 -1
- package/bundled/qc-helper/docs/features/commands.md +71 -6
- package/bundled/qc-helper/docs/features/computer-use.md +9 -7
- package/bundled/qc-helper/docs/features/followup-suggestions.md +2 -2
- package/bundled/qc-helper/docs/features/goals.md +15 -3
- package/bundled/qc-helper/docs/features/skills.md +40 -0
- package/bundled/qc-helper/docs/qwen-serve.md +19 -1
- package/chunks/{MaxSizedBox-5ARLO5PR.js → MaxSizedBox-UDO6Y7RB.js} +35 -36
- package/chunks/{StandaloneSessionPicker-T6B322CB.js → StandaloneSessionPicker-D4CUOO4H.js} +55 -56
- package/chunks/{acp-startup-profiler-6ULXXQMS.js → acp-startup-profiler-KEU6VAYR.js} +2 -2
- package/chunks/{acpAgent-WTDEY5KD.js → acpAgent-KWLJFADK.js} +210 -131
- package/chunks/{agent-NXPUXEVZ.js → agent-GSUPGEOL.js} +24 -25
- package/chunks/{agent-headless-QQZTWOKO.js → agent-headless-HNYCQUJB.js} +24 -25
- package/chunks/{anthropicContentGenerator-6XDHXIII.js → anthropicContentGenerator-I7LQZH26.js} +30 -7
- package/chunks/{artifact-tool-DFVVJXL2.js → artifact-tool-P52OKKEF.js} +1 -1
- package/chunks/{askUserQuestion-GF7VQ44M.js → askUserQuestion-I5W5S3D6.js} +2 -2
- package/chunks/{bridge-OHY5OGOZ.js → bridge-B7CV6RVI.js} +40 -41
- package/chunks/{channel-management-service-ZDDG3G5S.js → channel-management-service-TRTLQTSV.js} +4 -4
- package/chunks/{channel-settings-store-7BJAS2SU.js → channel-settings-store-FW45IRUP.js} +46 -47
- package/chunks/{channel-worker-group-2ISMRENV.js → channel-worker-group-PIYPVCTF.js} +6 -6
- package/chunks/{channel-worker-manager-VSRPVPRH.js → channel-worker-manager-FQHEDTD2.js} +6 -6
- package/chunks/{channel-worker-supervisor-SRJBK72Z.js → channel-worker-supervisor-XJPZZ3VK.js} +3 -3
- package/chunks/{chunk-2WGJG2KW.js → chunk-25CBAK3H.js} +4 -4
- package/chunks/{chunk-XUSOYE2I.js → chunk-27LTEY6D.js} +1 -1
- package/chunks/{chunk-WTW36TJ3.js → chunk-2EKVPSIJ.js} +1 -1
- package/chunks/{chunk-NAKALAL4.js → chunk-2TMJRF46.js} +116 -15
- package/chunks/{chunk-E4L5BM2B.js → chunk-2YS3NU4A.js} +4 -4
- package/chunks/chunk-2Z3T52OC.js +82 -0
- package/chunks/{chunk-ER273QE6.js → chunk-2ZFO5JD7.js} +21 -4
- package/chunks/{chunk-WXC6OAWD.js → chunk-3BTHHXXE.js} +1 -1
- package/chunks/{chunk-GXZHYPHZ.js → chunk-3LPJ776W.js} +5 -2
- package/chunks/{chunk-XY3USGFE.js → chunk-3VDLQUR2.js} +1 -1
- package/chunks/{chunk-LK7S2D6V.js → chunk-3VWPPK5Q.js} +58 -4
- package/chunks/{chunk-IKLFS6SC.js → chunk-3YQMUBTS.js} +3 -3
- package/chunks/{chunk-P4RUUG64.js → chunk-45ROPFQY.js} +1 -1
- package/chunks/{chunk-W4LL5RZO.js → chunk-4ALNJDHL.js} +52 -13
- package/chunks/{chunk-D6PIMKY3.js → chunk-4VY3ITHR.js} +4 -4
- package/chunks/{chunk-H3UDNQLO.js → chunk-5CVY5Q2P.js} +3 -3
- package/chunks/{chunk-6UIACMGH.js → chunk-5DQ4YTIZ.js} +1 -1
- package/chunks/{chunk-P6LATTDG.js → chunk-5IL2BZHW.js} +3 -3
- package/chunks/{chunk-537SQ2AI.js → chunk-5WC2ECUK.js} +104 -16
- package/chunks/{chunk-HFTB354P.js → chunk-5Z4FCEPY.js} +60 -6
- package/chunks/{chunk-3K65MUKD.js → chunk-65I7S4Z3.js} +2 -1
- package/chunks/{chunk-AQ5NAGWI.js → chunk-66JBCTJF.js} +8 -7
- package/chunks/{chunk-54TF2ZIQ.js → chunk-6JXHO7LG.js} +3 -3
- package/chunks/{chunk-YCDL2SAS.js → chunk-6QILGINT.js} +2 -2
- package/chunks/{chunk-P5LDR7FI.js → chunk-6QV7Z74P.js} +3 -3
- package/chunks/{chunk-4HC4DYKN.js → chunk-6RZX2HIH.js} +1 -1
- package/chunks/{chunk-O45WBTNS.js → chunk-6SADVYQQ.js} +3 -3
- package/chunks/{chunk-KE3Q4JMY.js → chunk-6TPVIESH.js} +5 -7
- package/chunks/{chunk-2LD5U7Q3.js → chunk-6YEOCHSE.js} +29 -1
- package/chunks/{chunk-QWZOOIR3.js → chunk-75LBC7SV.js} +69 -12
- package/chunks/{chunk-7BZS4ZDV.js → chunk-7SL55L5H.js} +25 -18
- package/chunks/{chunk-O2GG7H4C.js → chunk-ARYNBBBM.js} +3 -3
- package/chunks/{chunk-CZACBHAW.js → chunk-B3EL44K3.js} +5 -5
- package/chunks/{chunk-VY6UVU7G.js → chunk-CABDNUJ4.js} +2 -2
- package/chunks/{chunk-RVNS7NWN.js → chunk-CALNF3Z3.js} +1 -1
- package/chunks/{chunk-MWHY26G3.js → chunk-CHVU543W.js} +1 -1
- package/chunks/{chunk-GZWW2QWR.js → chunk-CIKL2DQP.js} +2 -2
- package/chunks/{chunk-R355CUNQ.js → chunk-CLKE4IY3.js} +1 -77
- package/chunks/{chunk-MUZCSTOO.js → chunk-CRZBDVP2.js} +5 -4
- package/chunks/{chunk-SFMCYMVF.js → chunk-D6AQNMUA.js} +4 -4
- package/chunks/{chunk-D4CU6DKR.js → chunk-DO5SMV52.js} +10 -8
- package/chunks/{chunk-ZAZ3NFL6.js → chunk-DXQ6Z7AH.js} +315 -63
- package/chunks/{chunk-IXSGOSEG.js → chunk-DZ6D4B3K.js} +28 -25
- package/chunks/{chunk-GMNLYQOS.js → chunk-E6TI726I.js} +1 -1
- package/chunks/{chunk-JBTZUFR4.js → chunk-E7XSUYCZ.js} +6 -6
- package/chunks/{chunk-AHBLRVD5.js → chunk-EEKU6COG.js} +4 -4
- package/chunks/{chunk-47BZVBTE.js → chunk-EHTKOO6W.js} +4 -4
- package/chunks/{chunk-HJ34U5J4.js → chunk-ENZDGHGJ.js} +4 -4
- package/chunks/{chunk-IFD3BTEA.js → chunk-EOET4H7C.js} +3 -3
- package/chunks/{chunk-ZTAVGFKA.js → chunk-ERXNTINK.js} +1 -1
- package/chunks/{chunk-F47DITLZ.js → chunk-FAWTMDX7.js} +14 -0
- package/chunks/{chunk-KPXRFTT7.js → chunk-FETY36NQ.js} +1 -1
- package/chunks/{chunk-5JLQWQK6.js → chunk-FV4DM2M4.js} +2 -2
- package/chunks/{chunk-4F2QRVW6.js → chunk-FW4E4QPG.js} +1 -1
- package/chunks/{chunk-KJJPJYHI.js → chunk-FWRRUITH.js} +8 -8
- package/chunks/{chunk-4VUVBN3Y.js → chunk-G6UUOCUT.js} +87 -0
- package/chunks/{chunk-4JAGXZR3.js → chunk-GM44O6F7.js} +1 -1
- package/chunks/{chunk-4MCY33Y2.js → chunk-GNY7B3CA.js} +1 -1
- package/chunks/{chunk-VEFRT7NX.js → chunk-H3Q3RSKZ.js} +1 -1
- package/chunks/{chunk-43NOB5NM.js → chunk-HIXUUCGY.js} +188 -13
- package/chunks/{chunk-EJNYBDYC.js → chunk-HNLMYDQE.js} +1 -1
- package/chunks/{chunk-JOPC3FND.js → chunk-HUX2DOTF.js} +5 -5
- package/chunks/{chunk-GCFZ2LAX.js → chunk-HZ2HUXX7.js} +2 -2
- package/chunks/{chunk-CWNC7M73.js → chunk-IKG2YVRZ.js} +2 -2
- package/chunks/{chunk-L4R7BCVV.js → chunk-J3TJH52D.js} +1 -1
- package/chunks/{chunk-QMFOYPGV.js → chunk-J3VZF2AL.js} +2 -2
- package/chunks/{chunk-ZJ2LM2SI.js → chunk-JGDRB4FP.js} +104 -33
- package/chunks/{chunk-LMJQSPWB.js → chunk-KA5HR3G2.js} +1 -1
- package/chunks/{chunk-G34YLYCS.js → chunk-L7V52QEZ.js} +10 -10
- package/chunks/{chunk-GVVCLL2P.js → chunk-LNCNUMJ5.js} +451 -396
- package/chunks/{chunk-RDKXZ2LS.js → chunk-LYT2OU7D.js} +1 -1
- package/chunks/{chunk-SAZS4IWW.js → chunk-LZGFVUWZ.js} +3 -3
- package/chunks/{chunk-32YDNYXP.js → chunk-M73KHGNR.js} +13 -66
- package/chunks/{chunk-ADJD4LZF.js → chunk-MA5OUNN6.js} +1 -1
- package/chunks/{chunk-2RYWGYB3.js → chunk-MFYH2VXV.js} +3 -3
- package/chunks/{chunk-RPBMP6BN.js → chunk-MWIO7MF6.js} +3 -0
- package/chunks/{chunk-OECNP26L.js → chunk-N6S3NUYJ.js} +1 -1
- package/chunks/{chunk-5MTARK4Y.js → chunk-N7YQEKGX.js} +6 -6
- package/chunks/{chunk-XOVVCGZX.js → chunk-NB3NDQQK.js} +1 -1
- package/chunks/chunk-NOO4QFXM.js +171 -0
- package/chunks/{chunk-NGX4NUNP.js → chunk-O2FEO2CB.js} +131 -6
- package/chunks/{chunk-XHGGYCTA.js → chunk-O2JBJQCF.js} +1 -1
- package/chunks/{chunk-LPBQODMR.js → chunk-OESZTXTG.js} +4 -4
- package/chunks/{chunk-UKADFFL2.js → chunk-OFVAS4AR.js} +1 -1
- package/chunks/{chunk-TDP7UULF.js → chunk-OPMKGOLD.js} +1 -1
- package/chunks/{chunk-LDS57224.js → chunk-OWCFKIFQ.js} +1 -1
- package/chunks/{chunk-I72PHOKL.js → chunk-PDUMGZ2P.js} +1524 -1382
- package/chunks/{chunk-JRYL3T2O.js → chunk-PQSCGZT2.js} +1 -1
- package/chunks/{chunk-WEXA2DNG.js → chunk-PSPAM24S.js} +14 -0
- package/chunks/{chunk-UKKYOIVT.js → chunk-QAZ2MGYT.js} +2 -2
- package/chunks/{chunk-J3O5I5ZD.js → chunk-QK4K76T6.js} +3 -3
- package/chunks/{chunk-NUQFUXOG.js → chunk-QTNCGZHQ.js} +2 -0
- package/chunks/{chunk-5YY5MZT6.js → chunk-QZOXVQPK.js} +1 -1
- package/chunks/{chunk-QJVZLILI.js → chunk-R7OO56VZ.js} +1 -1
- package/chunks/{chunk-IQN2CCIE.js → chunk-RNYENHN5.js} +398 -55
- package/chunks/{chunk-64MQTIX7.js → chunk-RPFJJ33Z.js} +2 -2
- package/chunks/{chunk-4VZCORNT.js → chunk-RXT4QBDX.js} +1 -1
- package/chunks/{chunk-SN5FV4FY.js → chunk-S6QVI3MV.js} +3 -3
- package/chunks/{chunk-NXWYCSPL.js → chunk-SOA4HKRJ.js} +1 -1
- package/chunks/{chunk-JLWFGYXU.js → chunk-T2IHCZLS.js} +2 -2
- package/chunks/{chunk-DNPHKA72.js → chunk-TGC4264Q.js} +6 -6
- package/chunks/{chunk-PZV2FASB.js → chunk-TRWQQBVH.js} +1 -1
- package/chunks/{chunk-Y3ZKI4RQ.js → chunk-TWAMIEQ2.js} +85 -22
- package/chunks/{chunk-KK2GZGBK.js → chunk-TWWS7XUW.js} +14 -11
- package/chunks/{chunk-4IQKBLTQ.js → chunk-UHUT4IDM.js} +18 -9
- package/chunks/{chunk-BKNY7PDI.js → chunk-USN6VNTO.js} +1 -1
- package/chunks/{chunk-TMWB67LS.js → chunk-UXDVUFKU.js} +3 -3
- package/chunks/{chunk-HY3DXYZK.js → chunk-UYDQYDW2.js} +1 -1
- package/chunks/{chunk-3K456UJF.js → chunk-VF6D6EGV.js} +12 -4
- package/chunks/{chunk-PZUOHCWI.js → chunk-WAASYFPK.js} +2 -2
- package/chunks/{chunk-OHOO527W.js → chunk-WG7BL3FY.js} +52 -2
- package/chunks/{chunk-JPEAQJNS.js → chunk-WJDXKQIO.js} +1 -1
- package/chunks/{chunk-MNEYUNOE.js → chunk-WNISCNTA.js} +40 -2
- package/chunks/{chunk-Z6WZPXQH.js → chunk-WQMUGQ6G.js} +2 -2
- package/chunks/{chunk-N7VURC4O.js → chunk-WXFCI3O5.js} +2 -2
- package/chunks/{chunk-VU7O7CGQ.js → chunk-XDNFODER.js} +1 -1
- package/chunks/{chunk-N7EYO2E7.js → chunk-XQ4RDO5B.js} +1 -1
- package/chunks/{chunk-VDXYYVCD.js → chunk-XVTCSVBK.js} +579 -57
- package/chunks/{chunk-PTFFWTTO.js → chunk-XZ3Z43XL.js} +3 -3
- package/chunks/{chunk-QSC5YOEC.js → chunk-YAC7H4K3.js} +2 -2
- package/chunks/{chunk-43JNQAHO.js → chunk-YCEKI7QX.js} +51 -10
- package/chunks/{chunk-7IKXTGZT.js → chunk-YI2YCNSP.js} +1 -1
- package/chunks/{chunk-VUSSAGKI.js → chunk-YZTGGCEE.js} +10 -2
- package/chunks/{chunk-WR3SH3EY.js → chunk-ZNO5BUAD.js} +149 -66
- package/chunks/{chunk-URSCX7S7.js → chunk-ZPL2TZNA.js} +353 -11
- package/chunks/{chunk-UEZOXZNI.js → chunk-ZU2T5JIS.js} +804 -371
- package/chunks/{config-utils-QXDOTXEQ.js → config-utils-KTDSQ4MU.js} +39 -40
- package/chunks/{contextCommand-RN4KARWC.js → contextCommand-UQ3KRYGK.js} +37 -38
- package/chunks/{core-runtime-NAZCOKHB.js → core-runtime-JR34JAFH.js} +35 -36
- package/chunks/{create-sub-session-BCSM4WKB.js → create-sub-session-RGPJOI4S.js} +45 -40
- package/chunks/{create-sub-session-BQ3SE4TX.js → create-sub-session-TGIX63YU.js} +2 -2
- package/chunks/{cron-create-D6HQ7I7I.js → cron-create-GTPVMJCF.js} +1 -1
- package/chunks/{cron-delete-KK3D2SQV.js → cron-delete-ZBK27Z4K.js} +1 -1
- package/chunks/{cron-list-VBF3IZMF.js → cron-list-KTFKFDKC.js} +1 -1
- package/chunks/{daemon-LCUELM6E.js → daemon-UI6SQSBV.js} +1 -1
- package/chunks/{daemon-git-worktree-guard-3K5CAU36.js → daemon-git-worktree-guard-H3OA26KQ.js} +35 -36
- package/chunks/{daemon-status-provider-4X3ZZQTZ.js → daemon-status-provider-6WZLKSZU.js} +45 -46
- package/chunks/{daemon-trust-policy-R45CFUJA.js → daemon-trust-policy-3EDP2BYD.js} +42 -43
- package/chunks/{daemon-trust-policy-monitor-DSSFCO3K.js → daemon-trust-policy-monitor-CRHZPK52.js} +42 -43
- package/chunks/{deferred-core-runtime-UO2M6WYI.js → deferred-core-runtime-LO5NTQQ4.js} +35 -36
- package/chunks/{discovery-TUM3ZQ6U.js → discovery-XP4RMDUM.js} +4 -2
- package/chunks/{display-image-EVVTBVYE.js → display-image-CTNHJRZC.js} +4 -4
- package/chunks/{dist-SIHF5MU2.js → dist-24TCWK5H.js} +1 -1
- package/chunks/{dist-AFH3BMZZ.js → dist-5I4HLUTO.js} +1 -1
- package/chunks/{dist-3T5MDUHP.js → dist-FDISN4AK.js} +1 -1
- package/chunks/{dist-SB2XRXZA.js → dist-M4CBX53H.js} +1 -1
- package/chunks/{dist-UVHW2U56.js → dist-NQ2636VT.js} +1 -1
- package/chunks/{dist-PH5RSTEA.js → dist-OR2ZQTXZ.js} +1 -1
- package/chunks/{dist-MK5PPBRF.js → dist-STAGIFNB.js} +1099 -67
- package/chunks/{dist-R5Y34V6T.js → dist-WZTUKIDR.js} +2 -2
- package/chunks/{dist-QUU7TVE3.js → dist-XJ25G6OH.js} +1 -1
- package/chunks/{edit-VNBCTRWP.js → edit-LB7Z7XK5.js} +24 -25
- package/chunks/{en-JMR535HP.js → en-YJNRUQG4.js} +1 -1
- package/chunks/{enter-worktree-CEVK7MQ2.js → enter-worktree-YFTKHXHZ.js} +4 -4
- package/chunks/{enterPlanMode-4KMZMUIA.js → enterPlanMode-P6TVUFIY.js} +24 -25
- package/chunks/{environment-S2HYQDON.js → environment-QATJNNKI.js} +38 -39
- package/chunks/{errors-DAAN5TL7.js → errors-3XJ37PS2.js} +37 -38
- package/chunks/{exit-worktree-D3YE6MUN.js → exit-worktree-NF2XEMES.js} +5 -5
- package/chunks/{exitPlanMode-HR36HG3D.js → exitPlanMode-A3OKL5UO.js} +24 -25
- package/chunks/{fast-path-4IWSW3UV.js → fast-path-DBIT5YQQ.js} +3 -3
- package/chunks/{fast-path-settings-ISEJPRYE.js → fast-path-settings-SATXY3PD.js} +3 -3
- package/chunks/{glob-IZYB2XH2.js → glob-73EDTXUE.js} +24 -25
- package/chunks/{goal-tools-VGUPKQDJ.js → goal-tools-DFI6YMSD.js} +24 -25
- package/chunks/{grep-OUVLNXG7.js → grep-BLHF2S5D.js} +2 -2
- package/chunks/{handleAutoUpdate-D56FMDTW.js → handleAutoUpdate-2FUNJO3B.js} +38 -39
- package/chunks/{i18n-BKE5WO6T.js → i18n-FDIA6KFI.js} +38 -37
- package/chunks/{image-gen-SHVQ3XID.js → image-gen-XP4NNIYG.js} +5 -5
- package/chunks/{initializer-MS4SGEHF.js → initializer-4MJTJOTW.js} +42 -43
- package/chunks/{installationInfo-542MGC4S.js → installationInfo-232RA2OK.js} +35 -36
- package/chunks/{list-H6XTKUWL.js → list-WN6WSGEB.js} +45 -46
- package/chunks/{list-agents-ULYBGJXC.js → list-agents-I5TRH3J7.js} +2 -2
- package/chunks/{llm-3NUC4EJY.js → llm-UDFWQWZA.js} +77 -78
- package/chunks/{llm-content-generator-R4NL3OQN.js → llm-content-generator-VLMZ2A7A.js} +23 -8
- package/chunks/{loadedSettingsAdapter-3XLKYDVT.js → loadedSettingsAdapter-OBQEIXM7.js} +42 -43
- package/chunks/{loggingContentGenerator-ZYSWVNEO.js → loggingContentGenerator-RGVUMUVX.js} +26 -27
- package/chunks/{loop-wakeup-B27BEYRL.js → loop-wakeup-HL6XOWI4.js} +2 -2
- package/chunks/{ls-3IIMMVKF.js → ls-YV7RKLKY.js} +1 -1
- package/chunks/{lsp-VJAT7XKS.js → lsp-NO3AMRZT.js} +1 -1
- package/chunks/{managed-npm-update-L2I53ZAI.js → managed-npm-update-QBAJYCFU.js} +35 -36
- package/chunks/{mcp-4PIXQASW.js → mcp-OTIZZCPY.js} +42 -43
- package/chunks/{monitor-O2YQTOZZ.js → monitor-BV5XF6LL.js} +24 -25
- package/chunks/{nonInteractiveCli-LV7CDBA2.js → nonInteractiveCli-W6MUKDVJ.js} +79 -77
- package/chunks/{notebook-edit-4RE2ALH4.js → notebook-edit-HGBEKGTE.js} +24 -25
- package/chunks/{openaiContentGenerator-7ND7K5CP.js → openaiContentGenerator-NSU3ERBH.js} +15 -15
- package/chunks/{pidfile-UFTLQ7NP.js → pidfile-LE3TU4GE.js} +35 -36
- package/chunks/{processUtils-3XBB4FYV.js → processUtils-YFBGJK67.js} +2 -2
- package/chunks/{prompt-terminal-ledger-2QASOGMM.js → prompt-terminal-ledger-4W4W7DSO.js} +36 -37
- package/chunks/{qwenContentGenerator-AELTUTH6.js → qwenContentGenerator-HTA57WFC.js} +28 -29
- package/chunks/{qwenOAuth2-BS5D2LYV.js → qwenOAuth2-KX6LVYQ3.js} +4 -4
- package/chunks/{read-file-PDWHZPHX.js → read-file-KHPQ2MB6.js} +4 -4
- package/chunks/{read-mcp-resource-YXJZ75UB.js → read-mcp-resource-D3N75DGF.js} +1 -1
- package/chunks/{record-artifact-WJDOV6XU.js → record-artifact-Q5CRGJTP.js} +2 -2
- package/chunks/{report-findings-Q4UACKWR.js → report-findings-TJ34R7QK.js} +3 -3
- package/chunks/{request-shutdown-2YZ3E3GH.js → request-shutdown-LRKMTBAD.js} +6 -6
- package/chunks/{resumeHistoryUtils-QRXZEEBA.js → resumeHistoryUtils-K7RV3QBN.js} +39 -40
- package/chunks/{ripGrep-KSOOLE6H.js → ripGrep-NBBVCMG4.js} +7 -7
- package/chunks/{run-qwen-serve-RTAREPT6.js → run-qwen-serve-A3JBOZCM.js} +58 -60
- package/chunks/{runtime-ESFSCJRZ.js → runtime-7YOU2KJ3.js} +47 -48
- package/chunks/{scheduled-tasks-6ZHRNBH6.js → scheduled-tasks-52LXK7LN.js} +42 -43
- package/chunks/{scheduler-DQI6KV7T.js → scheduler-J44M72VM.js} +37 -38
- package/chunks/{send-message-PQCVSVMN.js → send-message-AWKUDJBH.js} +8 -8
- package/chunks/{serve-FY7ZEW52.js → serve-TRC6XJUB.js} +42 -43
- package/chunks/{server-KNDY6K5F.js → server-YPNTJLX2.js} +1314 -841
- package/chunks/{session-MCEPXAZP.js → session-FMMIBFYX.js} +98 -84
- package/chunks/{session-attachments-root-OLNAE6GF.js → session-attachments-root-LDJMNK7K.js} +35 -36
- package/chunks/{session-pr-refresh-HKJHQQQK.js → session-pr-refresh-NLR4EK2J.js} +41 -42
- package/chunks/{settings-VXO4WBMK.js → settings-A46L577J.js} +41 -42
- package/chunks/{shell-U263OTES.js → shell-Q5LSQPPY.js} +24 -25
- package/chunks/{skill-SDODGBKL.js → skill-75KPJRCM.js} +10 -57
- package/chunks/{skill-settings-YEIA22QJ.js → skill-settings-775YT4YR.js} +41 -42
- package/chunks/{spawnChannel-4WJZVFPP.js → spawnChannel-XY73I5CU.js} +37 -38
- package/chunks/{standalone-update-ZWVQUO64.js → standalone-update-L46XXNQ2.js} +37 -38
- package/chunks/{start-opentui-ui-BFYCJQRZ.js → start-opentui-ui-WLV43247.js} +2007 -1003
- package/chunks/{startInteractiveUI-JYAFCMHL.js → startInteractiveUI-F5DKMLOV.js} +1231 -1528
- package/chunks/{syntheticOutput-AUAJBNXR.js → syntheticOutput-D2P5V6RG.js} +2 -2
- package/chunks/{task-create-LD5ISM3E.js → task-create-PMAFST2T.js} +7 -7
- package/chunks/{task-list-YISJ4RJA.js → task-list-R2HSY2NC.js} +1 -1
- package/chunks/{task-stop-65ZOVATJ.js → task-stop-BFSKRTGV.js} +1 -1
- package/chunks/{task-update-AAN4ZVEY.js → task-update-JYC57USF.js} +7 -7
- package/chunks/{team-create-KU7MABNO.js → team-create-2PATB77U.js} +24 -25
- package/chunks/{team-delete-XFRRTJTT.js → team-delete-CBHVBTPB.js} +1 -1
- package/chunks/{team-plan-approval-DPB377A3.js → team-plan-approval-QTANEWOS.js} +24 -25
- package/chunks/{terminal-image-renderer-WGWRENOF.js → terminal-image-renderer-OGULCFNF.js} +37 -38
- package/chunks/{theme-manager-GBUFULSO.js → theme-manager-CNO3QERP.js} +35 -36
- package/chunks/{todoWrite-G7NT4IFP.js → todoWrite-5ERKFWAK.js} +3 -5
- package/chunks/{tool-search-6YUXHBPT.js → tool-search-VXWEOZE7.js} +9 -9
- package/chunks/{total-session-admission-54R2JQ5L.js → total-session-admission-4KAADZPB.js} +41 -42
- package/chunks/{trustedFolders-KAJIDJTH.js → trustedFolders-PPJSOPOT.js} +36 -37
- package/chunks/{update-relaunch-XM4IWBFD.js → update-relaunch-4PT4MW7B.js} +5 -5
- package/chunks/{updateCheck-W6UZFURI.js → updateCheck-WAVFLWNG.js} +37 -38
- package/chunks/{useAutoAcceptIndicator-LAWYHY3U.js → useAutoAcceptIndicator-XNED4NRB.js} +44 -45
- package/chunks/{validateNonInterActiveAuth-7WCKHRN2.js → validateNonInterActiveAuth-J676DUQ2.js} +74 -74
- package/chunks/{version-3ZU43RJ6.js → version-J6SRRQB2.js} +1 -1
- package/chunks/{web-fetch-QHI2SQL4.js → web-fetch-FMZZYX44.js} +7 -7
- package/chunks/{web-search-3KZZKWNY.js → web-search-3G2KXCX5.js} +19 -8
- package/chunks/{workflow-HRW7Y2X4.js → workflow-PPZZICQ7.js} +26 -27
- package/chunks/{workspace-providers-status-KTGCWCPC.js → workspace-providers-status-IIYTAQST.js} +46 -47
- package/chunks/{workspace-registration-store-LHLPPWNE.js → workspace-registration-store-VHCDXAV7.js} +1 -1
- package/chunks/{workspace-registry-X34MLN52.js → workspace-registry-I7VQIPS2.js} +41 -42
- package/chunks/{workspace-runtime-coordinator-U4PW4P7K.js → workspace-runtime-coordinator-DBGNY32G.js} +41 -42
- package/chunks/{workspace-service-KD7BCGYL.js → workspace-service-QSKB2T54.js} +47 -48
- package/chunks/{workspace-skills-status-YJGO6Y3T.js → workspace-skills-status-T7GPT65J.js} +43 -44
- package/chunks/{workspace-trust-reconciler-EUYHISCH.js → workspace-trust-reconciler-2PKRDAU4.js} +48 -49
- package/chunks/{write-file-EBSB34NJ.js → write-file-L76CGFTQ.js} +26 -27
- package/chunks/{zh-TW-W2GNP2IU.js → zh-TW-N2TBF2F2.js} +1 -1
- package/chunks/{zh-DVFYHRK5.js → zh-VBFCRQBL.js} +1 -1
- package/chunks/{zoom-image-UJ5VKWKP.js → zoom-image-TDJJY2VZ.js} +4 -4
- package/cli.js +13 -13
- package/export-transcript-document.js +126 -122
- package/locales/en.js +2 -2
- package/locales/zh-TW.js +2 -2
- package/locales/zh.js +2 -2
- package/package.json +3 -3
- package/web-shell/assets/{abnfDiagram-VCTEODGH-Dur--luQ.js → abnfDiagram-VCTEODGH-DHc6plZn.js} +1 -1
- package/web-shell/assets/{arc-tYLobxFi.js → arc-BQ9m8TDV.js} +1 -1
- package/web-shell/assets/{architectureDiagram-5GKGNRK7-IG6aXD03.js → architectureDiagram-5GKGNRK7-D5ap3oVB.js} +1 -1
- package/web-shell/assets/{blockDiagram-NRAW4CY4-C6eBSkfA.js → blockDiagram-NRAW4CY4-BIbnyNph.js} +1 -1
- package/web-shell/assets/{c4Diagram-UCG6FXSJ-BrX3HJqB.js → c4Diagram-UCG6FXSJ-BRsdx_iG.js} +1 -1
- package/web-shell/assets/channel-uMMdTrYk.js +1 -0
- package/web-shell/assets/{chunk-2Q5K7J3B-B3fcJ8ee.js → chunk-2Q5K7J3B-3lf1fNlx.js} +1 -1
- package/web-shell/assets/{chunk-5VM5RSS4-CeC90yKM.js → chunk-5VM5RSS4-DP8VNRc4.js} +1 -1
- package/web-shell/assets/{chunk-F27PBJKO-CW44RVki.js → chunk-F27PBJKO-DrohDmZ6.js} +1 -1
- package/web-shell/assets/{chunk-G27WJ6UU-D1PAMukD.js → chunk-G27WJ6UU-UZ2QhSx6.js} +1 -1
- package/web-shell/assets/{chunk-JWPE2WC7-Dt3Y2Fvx.js → chunk-JWPE2WC7-BIMHVcZK.js} +1 -1
- package/web-shell/assets/{chunk-LCL6LL3I-CZHw2lLI.js → chunk-LCL6LL3I-izRxdSDd.js} +1 -1
- package/web-shell/assets/{chunk-POPQ4Y6H-ysNAdTGx.js → chunk-POPQ4Y6H-CXADD4PP.js} +1 -1
- package/web-shell/assets/{chunk-SVP7TREG-BdNXW6YQ.js → chunk-SVP7TREG-B96d8Y_1.js} +1 -1
- package/web-shell/assets/{chunk-XXDRQBXY-DgqQ9UA8.js → chunk-XXDRQBXY-CF2sVQpv.js} +1 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-DcY-26Ig.js +1 -0
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-DcY-26Ig.js +1 -0
- package/web-shell/assets/{cose-bilkent-JH36ORCC-BILImXzJ.js → cose-bilkent-JH36ORCC-CT6tXVAS.js} +1 -1
- package/web-shell/assets/csv-CX7rUNeC.svg +1 -0
- package/web-shell/assets/{cynefin-OW5HDTMX-DR88Pund.js → cynefin-OW5HDTMX-X1NS4vtV.js} +1 -1
- package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-BYFbfkA6.js → cynefinDiagram-5FMLGOSQ-DNsKNOT4.js} +1 -1
- package/web-shell/assets/{dagre-3AP2YEHR-rfpyc6sX.js → dagre-3AP2YEHR-9-AHKqsb.js} +1 -1
- package/web-shell/assets/{diagram-S7CK7UJ4-BJxLmEwH.js → diagram-S7CK7UJ4-Bjgms7j6.js} +1 -1
- package/web-shell/assets/{diagram-UQ7AKVKN-H34xm7k3.js → diagram-UQ7AKVKN-h6bCprbE.js} +1 -1
- package/web-shell/assets/{diagram-VSXAHHWV-HYxhwNLx.js → diagram-VSXAHHWV-4SbQXVLt.js} +1 -1
- package/web-shell/assets/{diagram-VX7I27RA-BJazso8F.js → diagram-VX7I27RA-B5gPCzzB.js} +1 -1
- package/web-shell/assets/{diagram-Z3DM3KII-Clje1aNy.js → diagram-Z3DM3KII-DFJXIA3A.js} +1 -1
- package/web-shell/assets/{ebnfDiagram-PWID7BFC-M93YBkFh.js → ebnfDiagram-PWID7BFC-FwyaU7VY.js} +1 -1
- package/web-shell/assets/{erDiagram-SSCWMZ5O-DY8XzSHU.js → erDiagram-SSCWMZ5O-8vJQh2te.js} +1 -1
- package/web-shell/assets/{flowDiagram-A5DVABFB-CE6Aylcq.js → flowDiagram-A5DVABFB-BzA_1gMN.js} +1 -1
- package/web-shell/assets/{ganttDiagram-EL5Y4UJY-DI-5LL22.js → ganttDiagram-EL5Y4UJY-Co-ABbVX.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-C7BZWElk.js → gitGraphDiagram-WWUBYQGX-DW_FcyrX.js} +1 -1
- package/web-shell/assets/{index-DclFHns9.js → index-BbMXfhNG.js} +1 -1
- package/web-shell/assets/{index-CVyqwW7y.js → index-Bu-rZoJ-.js} +483 -475
- package/web-shell/assets/index-CsPwZ1ut.css +36 -0
- package/web-shell/assets/{infoDiagram-RXCK75RN-CGUSy4Pc.js → infoDiagram-RXCK75RN-BEgfhUFN.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-5VMMS53U-B5BVks9q.js → ishikawaDiagram-5VMMS53U-DCsMxQmc.js} +1 -1
- package/web-shell/assets/{journeyDiagram-EYS64GPL-CFh6Tf7h.js → journeyDiagram-EYS64GPL-DyIEYoHz.js} +1 -1
- package/web-shell/assets/{kanban-definition-3QL26DDD-B7TlxP7c.js → kanban-definition-3QL26DDD-CkxjqCNr.js} +1 -1
- package/web-shell/assets/{layout-Br_pZq2Q.js → layout-BEWc0Al9.js} +1 -1
- package/web-shell/assets/{linear-BVlP6fte.js → linear-CNuNxirL.js} +1 -1
- package/web-shell/assets/{mermaid.core-TrcYWoiF.js → mermaid.core-DZBre674.js} +6 -6
- package/web-shell/assets/{mindmap-definition-FBJOCRG2-BJ4LzqjZ.js → mindmap-definition-FBJOCRG2-CpafFz_F.js} +1 -1
- package/web-shell/assets/{pegDiagram-XKGWAZYB-1b_MxlOl.js → pegDiagram-XKGWAZYB-DfZqk_dq.js} +1 -1
- package/web-shell/assets/{pieDiagram-E7YTZNPT-B8zl0YhY.js → pieDiagram-E7YTZNPT-S0UWXlgC.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-AXDQQJYC-CIZO8ukl.js → quadrantDiagram-AXDQQJYC-dd37_Ohj.js} +1 -1
- package/web-shell/assets/{railroadDiagram-O6MQD6OU-CepHSbCj.js → railroadDiagram-O6MQD6OU-CH8NJZ7u.js} +1 -1
- package/web-shell/assets/{requirementDiagram-EFPCY7ZU-BCgxkcSW.js → requirementDiagram-EFPCY7ZU-CFdqWYih.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-P5KCCOFB-CE5CcoMM.js → sankeyDiagram-P5KCCOFB-CsddcEGD.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-DvgHi-d5.js → sequenceDiagram-WJ2MYXX4-BZ270mGw.js} +1 -1
- package/web-shell/assets/{sizeCapture-X5ZJPWSS-T-fAsCPX.js → sizeCapture-X5ZJPWSS-CGaS4DBV.js} +1 -1
- package/web-shell/assets/{stateDiagram-HBIQ2CUA-DYHaul-5.js → stateDiagram-HBIQ2CUA-COpIzMu6.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-D6qEVAji.js +1 -0
- package/web-shell/assets/{swimlanes-XN3QIQJK-Dbz3Qiej.js → swimlanes-XN3QIQJK-CMF889m3.js} +1 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-mem5Jj4m.js +8 -0
- package/web-shell/assets/{timeline-definition-24CTP7MA-9NVRts3N.js → timeline-definition-24CTP7MA-BelnxYz5.js} +1 -1
- package/web-shell/assets/{vennDiagram-4TSXK5OY-C7cb7vnH.js → vennDiagram-4TSXK5OY-CU-NRqIB.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-VM6X3IG4-CG-8Ddjm.js → wardleyDiagram-VM6X3IG4-CDNKqWh-.js} +1 -1
- package/web-shell/assets/{xychartDiagram-S5SC5T6Z-iGeYAcP4.js → xychartDiagram-S5SC5T6Z-CLqguL5D.js} +1 -1
- package/web-shell/index.html +6 -3
- package/chunks/chunk-3UMWOKJC.js +0 -78
- package/chunks/chunk-FKJM6JKY.js +0 -98
- package/chunks/chunk-IQAFKVXS.js +0 -22
- package/web-shell/assets/channel-uEkvKckd.js +0 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-DuPsnhWS.js +0 -1
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-DuPsnhWS.js +0 -1
- package/web-shell/assets/index-FO7JXPnH.css +0 -36
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-BcYho9a4.js +0 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-D6HsOIgX.js +0 -8
|
@@ -464,6 +464,33 @@ var CHANNEL_PROMPT_META_KEY = "qwen.channel.prompt";
|
|
|
464
464
|
var CHANNEL_BTW_METHOD = "qwen/control/session/btw";
|
|
465
465
|
var ACP_PRIVATE_PARENT_CAPABILITY_META_KEY = "qwen-code/private-parent-capability";
|
|
466
466
|
var ACP_PRIVATE_PARENT_CAPABILITY_ENV = "QWEN_CODE_PRIVATE_ACP_CAPABILITY";
|
|
467
|
+
function parseBackgroundResponseContext(value) {
|
|
468
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
469
|
+
return void 0;
|
|
470
|
+
}
|
|
471
|
+
const record = value;
|
|
472
|
+
const taskId = record["taskId"];
|
|
473
|
+
const status = record["status"];
|
|
474
|
+
const kind = record["kind"];
|
|
475
|
+
if (typeof taskId !== "string" || !taskId || typeof status !== "string" || !status || kind !== "agent" && kind !== "monitor" && kind !== "shell" && kind !== "workflow") {
|
|
476
|
+
return void 0;
|
|
477
|
+
}
|
|
478
|
+
const context = { taskId, status, kind };
|
|
479
|
+
for (const field of ["toolUseId", "label", "turnId"]) {
|
|
480
|
+
const fieldValue = record[field];
|
|
481
|
+
if (typeof fieldValue === "string" && fieldValue) {
|
|
482
|
+
context[field] = fieldValue;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (typeof record["turnComplete"] === "boolean") {
|
|
486
|
+
context.turnComplete = record["turnComplete"];
|
|
487
|
+
}
|
|
488
|
+
if (typeof record["partial"] === "boolean") {
|
|
489
|
+
context.partial = record["partial"];
|
|
490
|
+
}
|
|
491
|
+
return context;
|
|
492
|
+
}
|
|
493
|
+
__name(parseBackgroundResponseContext, "parseBackgroundResponseContext");
|
|
467
494
|
function resolvePromptImages(options) {
|
|
468
495
|
const images = options?.images && options.images.length > 0 ? options.images : options?.imageBase64 && options.imageMimeType ? [{ data: options.imageBase64, mimeType: options.imageMimeType }] : [];
|
|
469
496
|
return images.filter((image) => !!image && typeof image.data === "string" && image.data.length > 0 && typeof image.mimeType === "string" && image.mimeType.length > 0).map((image) => {
|
|
@@ -671,6 +698,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
671
698
|
channelLoopToolHandlers = [];
|
|
672
699
|
knownSessionIds = /* @__PURE__ */ new Set();
|
|
673
700
|
sessionBindingTokens = /* @__PURE__ */ new Map();
|
|
701
|
+
toolCallKindsBySession = /* @__PURE__ */ new Map();
|
|
674
702
|
channelLoopMcpRegistered = false;
|
|
675
703
|
channelLoopMcpRegistration = null;
|
|
676
704
|
pendingPermissions = /* @__PURE__ */ new Map();
|
|
@@ -716,6 +744,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
716
744
|
this.resolvePendingPermissions();
|
|
717
745
|
this.knownSessionIds.clear();
|
|
718
746
|
this.sessionBindingTokens.clear();
|
|
747
|
+
this.toolCallKindsBySession.clear();
|
|
719
748
|
this.connection = null;
|
|
720
749
|
this.child = null;
|
|
721
750
|
this.emit("disconnected", code, signal);
|
|
@@ -879,6 +908,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
879
908
|
if (!this.knownSessionIds.delete(sessionId))
|
|
880
909
|
return;
|
|
881
910
|
this.sessionBindingTokens.delete(sessionId);
|
|
911
|
+
this.toolCallKindsBySession.delete(sessionId);
|
|
882
912
|
this.resolvePendingPermissions(sessionId);
|
|
883
913
|
const conn = this.connection;
|
|
884
914
|
if (!conn || !this.isConnected)
|
|
@@ -903,6 +933,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
903
933
|
this.resolvePendingPermissions();
|
|
904
934
|
this.knownSessionIds.clear();
|
|
905
935
|
this.sessionBindingTokens.clear();
|
|
936
|
+
this.toolCallKindsBySession.clear();
|
|
906
937
|
if (this.child) {
|
|
907
938
|
this.child.kill();
|
|
908
939
|
this.child = null;
|
|
@@ -926,8 +957,11 @@ var AcpBridge = class extends EventEmitter {
|
|
|
926
957
|
}
|
|
927
958
|
const content = update["content"];
|
|
928
959
|
if (meta?.["qwenDiscreteMessage"] === true) {
|
|
929
|
-
if (meta["source"] === "background_notification_response" && meta["rewritten"] !== true
|
|
930
|
-
|
|
960
|
+
if (meta["source"] === "background_notification_response" && meta["rewritten"] !== true) {
|
|
961
|
+
const context = parseBackgroundResponseContext(meta["backgroundTask"]);
|
|
962
|
+
if (content?.type === "text" && (content.text || context?.turnComplete)) {
|
|
963
|
+
this.emit("backgroundResponse", sessionId, content.text ?? "", context);
|
|
964
|
+
}
|
|
931
965
|
} else if (meta["source"] === "vision_bridge_notice" && content?.type === "text" && content.text) {
|
|
932
966
|
this.emit("textChunk", sessionId, content.text);
|
|
933
967
|
}
|
|
@@ -938,19 +972,44 @@ var AcpBridge = class extends EventEmitter {
|
|
|
938
972
|
}
|
|
939
973
|
break;
|
|
940
974
|
}
|
|
941
|
-
case "tool_call":
|
|
975
|
+
case "tool_call":
|
|
976
|
+
case "tool_call_update": {
|
|
977
|
+
const toolCallId = update["toolCallId"] || "";
|
|
978
|
+
if (!toolCallId)
|
|
979
|
+
break;
|
|
980
|
+
const explicitKind = typeof update["kind"] === "string" ? update["kind"] : "";
|
|
981
|
+
const meta = update["_meta"];
|
|
982
|
+
if (type === "tool_call_update" && !explicitKind && update["status"] === "in_progress" && (meta?.["shellProgress"] !== void 0 || meta?.["subagentProgress"] === true)) {
|
|
983
|
+
break;
|
|
984
|
+
}
|
|
985
|
+
let sessionKinds = this.toolCallKindsBySession.get(sessionId);
|
|
986
|
+
const kind = explicitKind || sessionKinds?.get(toolCallId);
|
|
987
|
+
if (!kind)
|
|
988
|
+
break;
|
|
989
|
+
if (type === "tool_call" || explicitKind) {
|
|
990
|
+
const kinds = sessionKinds ?? /* @__PURE__ */ new Map();
|
|
991
|
+
kinds.set(toolCallId, kind);
|
|
992
|
+
this.toolCallKindsBySession.set(sessionId, kinds);
|
|
993
|
+
sessionKinds = kinds;
|
|
994
|
+
}
|
|
942
995
|
const event = {
|
|
943
996
|
sessionId,
|
|
944
|
-
toolCallId
|
|
945
|
-
kind
|
|
997
|
+
toolCallId,
|
|
998
|
+
kind,
|
|
946
999
|
title: update["title"] || "",
|
|
947
1000
|
status: update["status"] || "pending",
|
|
948
1001
|
rawInput: update["rawInput"]
|
|
949
1002
|
};
|
|
950
|
-
if (event.status === "pending" || event.status === "in_progress") {
|
|
1003
|
+
if (type === "tool_call" && (event.status === "pending" || event.status === "in_progress")) {
|
|
951
1004
|
this.emitResponseBoundary(sessionId);
|
|
952
1005
|
}
|
|
953
1006
|
this.emit("toolCall", event);
|
|
1007
|
+
if (event.status === "completed" || event.status === "failed") {
|
|
1008
|
+
sessionKinds?.delete(toolCallId);
|
|
1009
|
+
if (sessionKinds?.size === 0) {
|
|
1010
|
+
this.toolCallKindsBySession.delete(sessionId);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
954
1013
|
break;
|
|
955
1014
|
}
|
|
956
1015
|
case "plan": {
|
|
@@ -1733,6 +1792,49 @@ init_esbuild_shims();
|
|
|
1733
1792
|
import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, rmSync, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1734
1793
|
import { dirname as dirname3, isAbsolute, join as join4 } from "node:path";
|
|
1735
1794
|
import process2 from "node:process";
|
|
1795
|
+
function readDaemonHttpErrorCode(error) {
|
|
1796
|
+
let current = error;
|
|
1797
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
1798
|
+
if (typeof current !== "object" && typeof current !== "function" || current === null) {
|
|
1799
|
+
return void 0;
|
|
1800
|
+
}
|
|
1801
|
+
const record = current;
|
|
1802
|
+
if (record["name"] === "DaemonHttpError" && record["status"] === 409) {
|
|
1803
|
+
const body = record["body"];
|
|
1804
|
+
if (typeof body === "object" && body !== null && !Array.isArray(body)) {
|
|
1805
|
+
const code = body["code"];
|
|
1806
|
+
if (typeof code === "string" && code.length > 0)
|
|
1807
|
+
return code;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
current = record["cause"];
|
|
1811
|
+
}
|
|
1812
|
+
return void 0;
|
|
1813
|
+
}
|
|
1814
|
+
__name(readDaemonHttpErrorCode, "readDaemonHttpErrorCode");
|
|
1815
|
+
function readSupersededReplacementId(error) {
|
|
1816
|
+
let current = error;
|
|
1817
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
1818
|
+
if (typeof current !== "object" && typeof current !== "function" || current === null) {
|
|
1819
|
+
return void 0;
|
|
1820
|
+
}
|
|
1821
|
+
const record = current;
|
|
1822
|
+
if (record["name"] === "DaemonHttpError" && record["status"] === 409) {
|
|
1823
|
+
const body = record["body"];
|
|
1824
|
+
if (typeof body === "object" && body !== null && !Array.isArray(body)) {
|
|
1825
|
+
const typedBody = body;
|
|
1826
|
+
if (typedBody["code"] !== "worktree_session_superseded") {
|
|
1827
|
+
return void 0;
|
|
1828
|
+
}
|
|
1829
|
+
const replacement = typedBody["replacementSessionId"];
|
|
1830
|
+
return typeof replacement === "string" && replacement.length > 0 ? replacement : void 0;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
current = record["cause"];
|
|
1834
|
+
}
|
|
1835
|
+
return void 0;
|
|
1836
|
+
}
|
|
1837
|
+
__name(readSupersededReplacementId, "readSupersededReplacementId");
|
|
1736
1838
|
var SessionRouter = class {
|
|
1737
1839
|
static {
|
|
1738
1840
|
__name(this, "SessionRouter");
|
|
@@ -1743,9 +1845,11 @@ var SessionRouter = class {
|
|
|
1743
1845
|
// session ID → target
|
|
1744
1846
|
toCwd = /* @__PURE__ */ new Map();
|
|
1745
1847
|
// session ID → cwd
|
|
1848
|
+
toManagedMeta = /* @__PURE__ */ new Map();
|
|
1746
1849
|
creatingSessions = /* @__PURE__ */ new Map();
|
|
1747
1850
|
sessionLoadWindows = /* @__PURE__ */ new Set();
|
|
1748
1851
|
liveSessionIds = /* @__PURE__ */ new Set();
|
|
1852
|
+
staleBridgeBindings = /* @__PURE__ */ new Set();
|
|
1749
1853
|
routeTokens = /* @__PURE__ */ new Map();
|
|
1750
1854
|
lifecycleGeneration = 0;
|
|
1751
1855
|
bridge;
|
|
@@ -1767,6 +1871,7 @@ var SessionRouter = class {
|
|
|
1767
1871
|
setBridge(bridge) {
|
|
1768
1872
|
this.bridge = bridge;
|
|
1769
1873
|
this.liveSessionIds.clear();
|
|
1874
|
+
this.staleBridgeBindings.clear();
|
|
1770
1875
|
}
|
|
1771
1876
|
/** Set scope override for a specific channel. */
|
|
1772
1877
|
setChannelScope(channelName, scope) {
|
|
@@ -2042,12 +2147,12 @@ var SessionRouter = class {
|
|
|
2042
2147
|
this.endSessionLoad(loadWindow);
|
|
2043
2148
|
}
|
|
2044
2149
|
}
|
|
2045
|
-
async loadManagedSession(sessionId, target, workspaceCwd, expectedCwd = workspaceCwd, isolation = "shared") {
|
|
2150
|
+
async loadManagedSession(sessionId, target, workspaceCwd, expectedCwd = workspaceCwd, isolation = "shared", allowSupersededRedirect = true) {
|
|
2046
2151
|
if (this.liveSessionIds.has(sessionId)) {
|
|
2047
2152
|
const actualCwd = this.validateManagedSessionIdentity(this.bridge, sessionId, workspaceCwd, expectedCwd, isolation);
|
|
2048
2153
|
this.toTarget.set(sessionId, target);
|
|
2049
2154
|
this.toCwd.set(sessionId, actualCwd);
|
|
2050
|
-
return { loaded: false };
|
|
2155
|
+
return { loaded: false, sessionId };
|
|
2051
2156
|
}
|
|
2052
2157
|
const loadWindow = this.beginSessionLoad();
|
|
2053
2158
|
const lifecycleGeneration = this.lifecycleGeneration;
|
|
@@ -2055,6 +2160,9 @@ var SessionRouter = class {
|
|
|
2055
2160
|
const bindingToken = {};
|
|
2056
2161
|
let loadedSessionId;
|
|
2057
2162
|
try {
|
|
2163
|
+
if (this.staleBridgeBindings.delete(sessionId)) {
|
|
2164
|
+
await bridge.discardSession?.(sessionId).catch(() => void 0);
|
|
2165
|
+
}
|
|
2058
2166
|
loadedSessionId = await bridge.loadSession(sessionId, workspaceCwd, this.sessionOptions(target.channelName), bindingToken);
|
|
2059
2167
|
if (lifecycleGeneration !== this.lifecycleGeneration || bridge !== this.bridge) {
|
|
2060
2168
|
this.scheduleManagedDiscard(bridge, loadedSessionId, bindingToken);
|
|
@@ -2074,16 +2182,105 @@ var SessionRouter = class {
|
|
|
2074
2182
|
this.toTarget.set(sessionId, target);
|
|
2075
2183
|
this.toCwd.set(sessionId, actualCwd);
|
|
2076
2184
|
this.liveSessionIds.add(sessionId);
|
|
2077
|
-
return { loaded: true };
|
|
2185
|
+
return { loaded: true, sessionId };
|
|
2078
2186
|
} catch (error) {
|
|
2079
2187
|
if (loadedSessionId) {
|
|
2080
2188
|
await bridge.discardSession?.(loadedSessionId, bindingToken).catch(() => void 0);
|
|
2189
|
+
throw error;
|
|
2190
|
+
}
|
|
2191
|
+
const replacementId = readSupersededReplacementId(error);
|
|
2192
|
+
if (allowSupersededRedirect && replacementId !== void 0 && replacementId !== sessionId) {
|
|
2193
|
+
const redirected = await this.loadManagedSession(replacementId, target, workspaceCwd, expectedCwd, isolation, false);
|
|
2194
|
+
this.healSupersededRoute(sessionId, redirected.sessionId);
|
|
2195
|
+
return {
|
|
2196
|
+
loaded: redirected.loaded,
|
|
2197
|
+
sessionId: redirected.sessionId,
|
|
2198
|
+
redirectedFrom: sessionId
|
|
2199
|
+
};
|
|
2081
2200
|
}
|
|
2082
2201
|
throw error;
|
|
2083
2202
|
} finally {
|
|
2084
2203
|
this.endSessionLoad(loadWindow);
|
|
2085
2204
|
}
|
|
2086
2205
|
}
|
|
2206
|
+
/**
|
|
2207
|
+
* Remap every route that still points at a superseded session to its
|
|
2208
|
+
* replacement, and drop the superseded id's bookkeeping. The manager's
|
|
2209
|
+
* own task registry heals separately (it owns the task-name mapping).
|
|
2210
|
+
*/
|
|
2211
|
+
healSupersededRoute(oldSessionId, newSessionId) {
|
|
2212
|
+
let changed = false;
|
|
2213
|
+
for (const [key, mappedSessionId] of this.toSession) {
|
|
2214
|
+
if (mappedSessionId !== oldSessionId)
|
|
2215
|
+
continue;
|
|
2216
|
+
this.invalidateRouteOperation(key);
|
|
2217
|
+
this.toSession.set(key, newSessionId);
|
|
2218
|
+
changed = true;
|
|
2219
|
+
}
|
|
2220
|
+
changed = this.toTarget.delete(oldSessionId) || changed;
|
|
2221
|
+
changed = this.toCwd.delete(oldSessionId) || changed;
|
|
2222
|
+
const managedMeta = this.toManagedMeta.get(oldSessionId);
|
|
2223
|
+
if (managedMeta !== void 0) {
|
|
2224
|
+
this.toManagedMeta.set(newSessionId, managedMeta);
|
|
2225
|
+
this.toManagedMeta.delete(oldSessionId);
|
|
2226
|
+
changed = true;
|
|
2227
|
+
}
|
|
2228
|
+
this.liveSessionIds.delete(oldSessionId);
|
|
2229
|
+
this.staleBridgeBindings.delete(oldSessionId);
|
|
2230
|
+
if (changed)
|
|
2231
|
+
this.persist();
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Worktree reset: transfer the task session's checkout ownership to a
|
|
2235
|
+
* fresh replacement session on the daemon, validate the replacement's
|
|
2236
|
+
* attestation, and route it. The task registry itself is swapped by the
|
|
2237
|
+
* named-session manager (it owns the task-name mapping); this call only
|
|
2238
|
+
* wires the router's session bookkeeping.
|
|
2239
|
+
*
|
|
2240
|
+
* A failure past the daemon's marker flip rolls nothing back: the
|
|
2241
|
+
* registry keeps pointing at the old id, and the next selection's load
|
|
2242
|
+
* heals it through the superseded redirect — the failed reset drops the
|
|
2243
|
+
* old id from the live set so that load consults the daemon again.
|
|
2244
|
+
*/
|
|
2245
|
+
async replaceManagedWorktreeSession(sessionId, target, workspaceCwd, expectedCwd) {
|
|
2246
|
+
const bridge = this.bridge;
|
|
2247
|
+
if (!bridge.resetWorktreeSession) {
|
|
2248
|
+
throw new Error("Worktree reset is not supported by this bridge");
|
|
2249
|
+
}
|
|
2250
|
+
const loadWindow = this.beginSessionLoad();
|
|
2251
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
2252
|
+
const bindingToken = {};
|
|
2253
|
+
let replacementId;
|
|
2254
|
+
try {
|
|
2255
|
+
replacementId = await bridge.resetWorktreeSession(sessionId, workspaceCwd, this.sessionOptions(target.channelName), bindingToken);
|
|
2256
|
+
if (lifecycleGeneration !== this.lifecycleGeneration || bridge !== this.bridge) {
|
|
2257
|
+
this.scheduleManagedDiscard(bridge, replacementId, bindingToken);
|
|
2258
|
+
throw new Error("Managed session reset was invalidated");
|
|
2259
|
+
}
|
|
2260
|
+
if (typeof replacementId !== "string" || replacementId.length === 0) {
|
|
2261
|
+
throw new Error("Invalid session ID from bridge");
|
|
2262
|
+
}
|
|
2263
|
+
if (loadWindow.delete(replacementId)) {
|
|
2264
|
+
await bridge.discardSession?.(replacementId, bindingToken);
|
|
2265
|
+
throw new Error(`Managed session ${replacementId} died before reset completed`);
|
|
2266
|
+
}
|
|
2267
|
+
const actualCwd = this.validateManagedSessionIdentity(bridge, replacementId, workspaceCwd, expectedCwd, "worktree");
|
|
2268
|
+
this.toTarget.set(replacementId, target);
|
|
2269
|
+
this.toCwd.set(replacementId, actualCwd);
|
|
2270
|
+
this.liveSessionIds.add(replacementId);
|
|
2271
|
+
this.forgetManagedSession(sessionId);
|
|
2272
|
+
return replacementId;
|
|
2273
|
+
} catch (error) {
|
|
2274
|
+
if (replacementId !== void 0) {
|
|
2275
|
+
await bridge.discardSession?.(replacementId, bindingToken).catch(() => void 0);
|
|
2276
|
+
}
|
|
2277
|
+
this.staleBridgeBindings.add(sessionId);
|
|
2278
|
+
this.liveSessionIds.delete(sessionId);
|
|
2279
|
+
throw error;
|
|
2280
|
+
} finally {
|
|
2281
|
+
this.endSessionLoad(loadWindow);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2087
2284
|
validateManagedSessionIdentity(bridge, sessionId, workspaceCwd, expectedCwd, isolation) {
|
|
2088
2285
|
if (isolation === "shared") {
|
|
2089
2286
|
return workspaceCwd;
|
|
@@ -2096,10 +2293,26 @@ var SessionRouter = class {
|
|
|
2096
2293
|
}
|
|
2097
2294
|
return canonicalWorktree;
|
|
2098
2295
|
}
|
|
2099
|
-
activateManagedSession(sessionId, target, cwd) {
|
|
2296
|
+
activateManagedSession(sessionId, target, cwd, managed) {
|
|
2297
|
+
if (managed?.isolation === "worktree" && !managed.workspaceCwd) {
|
|
2298
|
+
throw new Error("A worktree managed session requires its workspace cwd.");
|
|
2299
|
+
}
|
|
2300
|
+
const previousMeta = this.toManagedMeta.get(sessionId);
|
|
2301
|
+
if (managed?.isolation === "worktree") {
|
|
2302
|
+
this.toManagedMeta.set(sessionId, {
|
|
2303
|
+
isolation: "worktree",
|
|
2304
|
+
workspaceCwd: managed.workspaceCwd
|
|
2305
|
+
});
|
|
2306
|
+
} else {
|
|
2307
|
+
this.toManagedMeta.delete(sessionId);
|
|
2308
|
+
}
|
|
2309
|
+
const metaChanged = managed?.isolation === "worktree" ? previousMeta?.workspaceCwd !== managed.workspaceCwd : previousMeta !== void 0;
|
|
2100
2310
|
const key = this.routingKey(target.channelName, target.senderId, target.chatId, target.threadId);
|
|
2101
|
-
if (this.toSession.get(key) === sessionId)
|
|
2311
|
+
if (this.toSession.get(key) === sessionId) {
|
|
2312
|
+
if (metaChanged)
|
|
2313
|
+
this.persist();
|
|
2102
2314
|
return;
|
|
2315
|
+
}
|
|
2103
2316
|
this.invalidateRouteOperation(key);
|
|
2104
2317
|
this.toSession.set(key, sessionId);
|
|
2105
2318
|
this.toTarget.set(sessionId, target);
|
|
@@ -2117,17 +2330,18 @@ var SessionRouter = class {
|
|
|
2117
2330
|
}
|
|
2118
2331
|
changed = this.toTarget.delete(sessionId) || changed;
|
|
2119
2332
|
changed = this.toCwd.delete(sessionId) || changed;
|
|
2333
|
+
changed = this.toManagedMeta.delete(sessionId) || changed;
|
|
2120
2334
|
changed = this.liveSessionIds.delete(sessionId) || changed;
|
|
2335
|
+
this.staleBridgeBindings.delete(sessionId);
|
|
2121
2336
|
if (changed)
|
|
2122
2337
|
this.persist();
|
|
2123
2338
|
}
|
|
2124
2339
|
async detachManagedSession(sessionId) {
|
|
2125
2340
|
try {
|
|
2126
|
-
if (this.
|
|
2127
|
-
if (!this.bridge.discardSession) {
|
|
2128
|
-
throw new Error("Managed session detach is not supported");
|
|
2129
|
-
}
|
|
2341
|
+
if (this.bridge.discardSession) {
|
|
2130
2342
|
await this.bridge.discardSession(sessionId);
|
|
2343
|
+
} else if (this.liveSessionIds.has(sessionId)) {
|
|
2344
|
+
throw new Error("Managed session detach is not supported");
|
|
2131
2345
|
}
|
|
2132
2346
|
} finally {
|
|
2133
2347
|
this.forgetManagedSession(sessionId);
|
|
@@ -2183,6 +2397,9 @@ var SessionRouter = class {
|
|
|
2183
2397
|
if (this.toCwd.delete(sessionId)) {
|
|
2184
2398
|
removed = true;
|
|
2185
2399
|
}
|
|
2400
|
+
if (this.toManagedMeta.delete(sessionId)) {
|
|
2401
|
+
removed = true;
|
|
2402
|
+
}
|
|
2186
2403
|
this.liveSessionIds.delete(sessionId);
|
|
2187
2404
|
if (!removed && this.sessionLoadWindows.size > 0) {
|
|
2188
2405
|
for (const loadWindow of this.sessionLoadWindows) {
|
|
@@ -2212,6 +2429,7 @@ var SessionRouter = class {
|
|
|
2212
2429
|
this.toSession.delete(key);
|
|
2213
2430
|
this.toTarget.delete(sessionId);
|
|
2214
2431
|
this.toCwd.delete(sessionId);
|
|
2432
|
+
this.toManagedMeta.delete(sessionId);
|
|
2215
2433
|
this.liveSessionIds.delete(sessionId);
|
|
2216
2434
|
return sessionId;
|
|
2217
2435
|
}
|
|
@@ -2248,6 +2466,12 @@ var SessionRouter = class {
|
|
|
2248
2466
|
this.toSession.set(key, entry.sessionId);
|
|
2249
2467
|
this.toTarget.set(entry.sessionId, entry.target);
|
|
2250
2468
|
this.toCwd.set(entry.sessionId, entry.cwd);
|
|
2469
|
+
if (entry.isolation === "worktree" && entry.workspaceCwd !== void 0) {
|
|
2470
|
+
this.toManagedMeta.set(entry.sessionId, {
|
|
2471
|
+
isolation: "worktree",
|
|
2472
|
+
workspaceCwd: entry.workspaceCwd
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2251
2475
|
restored++;
|
|
2252
2476
|
}
|
|
2253
2477
|
if (persisted.dropped > 0)
|
|
@@ -2291,6 +2515,32 @@ var SessionRouter = class {
|
|
|
2291
2515
|
try {
|
|
2292
2516
|
this.assertOperationCurrent(operation);
|
|
2293
2517
|
const options = this.sessionOptions(entry.target.channelName);
|
|
2518
|
+
if (entry.isolation === "worktree" && entry.workspaceCwd !== void 0) {
|
|
2519
|
+
const managed = await this.loadManagedSession(entry.sessionId, entry.target, entry.workspaceCwd, entry.cwd, "worktree");
|
|
2520
|
+
try {
|
|
2521
|
+
this.assertOperationCurrent(operation);
|
|
2522
|
+
} catch (error) {
|
|
2523
|
+
if (![...this.toSession.values()].includes(managed.sessionId)) {
|
|
2524
|
+
void this.bridge.discardSession?.(managed.sessionId).catch(() => void 0);
|
|
2525
|
+
this.toTarget.delete(managed.sessionId);
|
|
2526
|
+
this.toCwd.delete(managed.sessionId);
|
|
2527
|
+
this.toManagedMeta.delete(managed.sessionId);
|
|
2528
|
+
this.liveSessionIds.delete(managed.sessionId);
|
|
2529
|
+
}
|
|
2530
|
+
throw error;
|
|
2531
|
+
}
|
|
2532
|
+
this.toSession.set(key, managed.sessionId);
|
|
2533
|
+
this.toManagedMeta.set(managed.sessionId, {
|
|
2534
|
+
isolation: "worktree",
|
|
2535
|
+
workspaceCwd: entry.workspaceCwd
|
|
2536
|
+
});
|
|
2537
|
+
reservation.resolve(managed.sessionId);
|
|
2538
|
+
if (managed.sessionId !== entry.sessionId) {
|
|
2539
|
+
changed = true;
|
|
2540
|
+
}
|
|
2541
|
+
restored++;
|
|
2542
|
+
continue;
|
|
2543
|
+
}
|
|
2294
2544
|
const sessionId = await this.bridge.loadSession(entry.sessionId, entry.cwd, options, operation);
|
|
2295
2545
|
try {
|
|
2296
2546
|
this.assertOperationCurrent(operation);
|
|
@@ -2343,9 +2593,11 @@ var SessionRouter = class {
|
|
|
2343
2593
|
this.toSession.clear();
|
|
2344
2594
|
this.toTarget.clear();
|
|
2345
2595
|
this.toCwd.clear();
|
|
2596
|
+
this.toManagedMeta.clear();
|
|
2346
2597
|
this.creatingSessions.clear();
|
|
2347
2598
|
this.sessionLoadWindows.clear();
|
|
2348
2599
|
this.liveSessionIds.clear();
|
|
2600
|
+
this.staleBridgeBindings.clear();
|
|
2349
2601
|
this.routeTokens.clear();
|
|
2350
2602
|
}
|
|
2351
2603
|
/** Clear in-memory state and delete persist file. Used on clean shutdown. */
|
|
@@ -2403,7 +2655,12 @@ var SessionRouter = class {
|
|
|
2403
2655
|
if (typeof target !== "object" || target === null)
|
|
2404
2656
|
return false;
|
|
2405
2657
|
const typedTarget = target;
|
|
2406
|
-
|
|
2658
|
+
const wellFormed = typeof entry["sessionId"] === "string" && entry["sessionId"].length > 0 && typeof entry["cwd"] === "string" && entry["cwd"].length > 0 && typeof typedTarget["channelName"] === "string" && typeof typedTarget["senderId"] === "string" && typeof typedTarget["chatId"] === "string" && (typedTarget["threadId"] === void 0 || typeof typedTarget["threadId"] === "string") && (typedTarget["isGroup"] === void 0 || typeof typedTarget["isGroup"] === "boolean");
|
|
2659
|
+
if (!wellFormed)
|
|
2660
|
+
return false;
|
|
2661
|
+
if (entry["isolation"] === void 0)
|
|
2662
|
+
return true;
|
|
2663
|
+
return entry["isolation"] === "worktree" && typeof entry["workspaceCwd"] === "string" && entry["workspaceCwd"].length > 0;
|
|
2407
2664
|
}
|
|
2408
2665
|
persist() {
|
|
2409
2666
|
if (!this.persistPath)
|
|
@@ -2416,7 +2673,8 @@ var SessionRouter = class {
|
|
|
2416
2673
|
data[key] = {
|
|
2417
2674
|
sessionId,
|
|
2418
2675
|
target,
|
|
2419
|
-
cwd: this.toCwd.get(sessionId) ?? this.defaultCwd
|
|
2676
|
+
cwd: this.toCwd.get(sessionId) ?? this.defaultCwd,
|
|
2677
|
+
...this.toManagedMeta.get(sessionId) ?? {}
|
|
2420
2678
|
};
|
|
2421
2679
|
}
|
|
2422
2680
|
const dir = dirname3(this.persistPath);
|
|
@@ -2564,6 +2822,16 @@ import process3 from "node:process";
|
|
|
2564
2822
|
var REGISTRY_VERSION = 1;
|
|
2565
2823
|
var MAX_OPEN_TASKS = 8;
|
|
2566
2824
|
var TASK_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;
|
|
2825
|
+
var NamedSessionTaskError = class extends Error {
|
|
2826
|
+
static {
|
|
2827
|
+
__name(this, "NamedSessionTaskError");
|
|
2828
|
+
}
|
|
2829
|
+
taskName;
|
|
2830
|
+
constructor(message, taskName, options) {
|
|
2831
|
+
super(message, options);
|
|
2832
|
+
this.taskName = taskName;
|
|
2833
|
+
}
|
|
2834
|
+
};
|
|
2567
2835
|
var NamedSessionManager = class {
|
|
2568
2836
|
static {
|
|
2569
2837
|
__name(this, "NamedSessionManager");
|
|
@@ -2578,6 +2846,12 @@ var NamedSessionManager = class {
|
|
|
2578
2846
|
registry;
|
|
2579
2847
|
taskBySessionId;
|
|
2580
2848
|
ownerOperations = /* @__PURE__ */ new Map();
|
|
2849
|
+
/**
|
|
2850
|
+
* Superseded session id → the replacement its task moved onto. A queued turn
|
|
2851
|
+
* stays bound to the id it reserved, so the reservation lookup has to follow
|
|
2852
|
+
* the task or every turn after the first one is stranded on the old id.
|
|
2853
|
+
*/
|
|
2854
|
+
supersededSessionIds = /* @__PURE__ */ new Map();
|
|
2581
2855
|
constructor(options) {
|
|
2582
2856
|
this.channelName = options.channelName;
|
|
2583
2857
|
this.cwd = options.cwd;
|
|
@@ -2676,14 +2950,20 @@ var NamedSessionManager = class {
|
|
|
2676
2950
|
return task ? this.selection(owner, task) : void 0;
|
|
2677
2951
|
});
|
|
2678
2952
|
}
|
|
2953
|
+
/**
|
|
2954
|
+
* Reload a task a queued turn is already bound to. Resolves to the session
|
|
2955
|
+
* id the caller must dispatch on — the healed replacement when a superseded
|
|
2956
|
+
* redirect fired — or undefined when the task is no longer reservable.
|
|
2957
|
+
*/
|
|
2679
2958
|
resumeReserved(input, sessionId) {
|
|
2680
2959
|
return this.withOwnerLock(input, async () => {
|
|
2681
2960
|
const owner = await this.ensureOwner(input, false);
|
|
2682
|
-
const
|
|
2961
|
+
const reservedSessionId = this.supersededSessionIds.get(sessionId) ?? sessionId;
|
|
2962
|
+
const task = owner?.tasks.find((candidate) => candidate.sessionId === reservedSessionId && candidate.status === "open");
|
|
2683
2963
|
if (!task)
|
|
2684
|
-
return
|
|
2685
|
-
await this.loadTask(task, `Could not reload reserved task "${task.name}".`);
|
|
2686
|
-
return
|
|
2964
|
+
return void 0;
|
|
2965
|
+
const result = await this.loadTask(task, `Could not reload reserved task "${task.name}".`);
|
|
2966
|
+
return result.sessionId;
|
|
2687
2967
|
});
|
|
2688
2968
|
}
|
|
2689
2969
|
create(input, name, isolation = "shared") {
|
|
@@ -2727,7 +3007,10 @@ var NamedSessionManager = class {
|
|
|
2727
3007
|
await this.router.detachManagedSession(sessionId).catch(() => void 0);
|
|
2728
3008
|
throw error;
|
|
2729
3009
|
}
|
|
2730
|
-
this.router.activateManagedSession(sessionId, target, task.cwd
|
|
3010
|
+
this.router.activateManagedSession(sessionId, target, task.cwd, {
|
|
3011
|
+
isolation: task.isolation,
|
|
3012
|
+
workspaceCwd: this.cwd
|
|
3013
|
+
});
|
|
2731
3014
|
return this.selection(nextOwner, task);
|
|
2732
3015
|
});
|
|
2733
3016
|
}
|
|
@@ -2743,9 +3026,10 @@ var NamedSessionManager = class {
|
|
|
2743
3026
|
throw new Error("You already have eight open tasks. Close one before reopening another.");
|
|
2744
3027
|
}
|
|
2745
3028
|
const timestamp = this.nextTimestamp(owner);
|
|
2746
|
-
const
|
|
3029
|
+
const loadResult = await this.loadTask(task, `Could not load task "${task.name}". The current task was not changed.`);
|
|
2747
3030
|
const updatedTask = {
|
|
2748
3031
|
...task,
|
|
3032
|
+
sessionId: loadResult.sessionId,
|
|
2749
3033
|
status: "open",
|
|
2750
3034
|
updatedAt: timestamp,
|
|
2751
3035
|
lastSelectedAt: timestamp
|
|
@@ -2754,12 +3038,12 @@ var NamedSessionManager = class {
|
|
|
2754
3038
|
try {
|
|
2755
3039
|
this.commitOwner(nextOwner);
|
|
2756
3040
|
} catch (error) {
|
|
2757
|
-
if (loaded) {
|
|
2758
|
-
await this.router.detachManagedSession(
|
|
3041
|
+
if (loadResult.loaded) {
|
|
3042
|
+
await this.router.detachManagedSession(loadResult.sessionId).catch(() => void 0);
|
|
2759
3043
|
}
|
|
2760
3044
|
throw error;
|
|
2761
3045
|
}
|
|
2762
|
-
this.router.activateManagedSession(
|
|
3046
|
+
this.router.activateManagedSession(loadResult.sessionId, updatedTask.target, updatedTask.cwd, { isolation: updatedTask.isolation, workspaceCwd: this.cwd });
|
|
2763
3047
|
return this.selection(nextOwner, updatedTask);
|
|
2764
3048
|
});
|
|
2765
3049
|
}
|
|
@@ -2781,8 +3065,11 @@ var NamedSessionManager = class {
|
|
|
2781
3065
|
const timestamp = this.nextTimestamp(owner);
|
|
2782
3066
|
const replacement = wasActive ? owner.tasks.filter((candidate) => candidate.status === "open" && !this.sameName(candidate.name, task.name)).sort((a, b) => b.lastSelectedAt - a.lastSelectedAt)[0] : void 0;
|
|
2783
3067
|
let replacementLoaded = false;
|
|
3068
|
+
let replacementSessionId;
|
|
2784
3069
|
if (replacement) {
|
|
2785
|
-
|
|
3070
|
+
const replacementLoad = await this.loadTask(replacement, `Could not load fallback task "${replacement.name}". Task "${task.name}" was not closed.`);
|
|
3071
|
+
replacementLoaded = replacementLoad.loaded;
|
|
3072
|
+
replacementSessionId = replacementLoad.sessionId;
|
|
2786
3073
|
}
|
|
2787
3074
|
const closedTask = {
|
|
2788
3075
|
...task,
|
|
@@ -2792,6 +3079,7 @@ var NamedSessionManager = class {
|
|
|
2792
3079
|
let nextOwner = this.replaceTask(owner, closedTask, wasActive ? replacement?.name ?? null : owner.activeTaskName);
|
|
2793
3080
|
const selectedReplacement = replacement ? {
|
|
2794
3081
|
...replacement,
|
|
3082
|
+
sessionId: replacementSessionId ?? replacement.sessionId,
|
|
2795
3083
|
updatedAt: timestamp,
|
|
2796
3084
|
lastSelectedAt: timestamp
|
|
2797
3085
|
} : void 0;
|
|
@@ -2802,21 +3090,22 @@ var NamedSessionManager = class {
|
|
|
2802
3090
|
this.commitOwner(nextOwner);
|
|
2803
3091
|
} catch (error) {
|
|
2804
3092
|
if (replacement && replacementLoaded) {
|
|
2805
|
-
await this.router.detachManagedSession(replacement.sessionId).catch(() => void 0);
|
|
3093
|
+
await this.router.detachManagedSession(replacementSessionId ?? replacement.sessionId).catch(() => void 0);
|
|
2806
3094
|
}
|
|
2807
3095
|
throw error;
|
|
2808
3096
|
}
|
|
2809
3097
|
if (replacement) {
|
|
2810
|
-
this.router.activateManagedSession(replacement.sessionId, replacement.target, replacement.cwd);
|
|
3098
|
+
this.router.activateManagedSession(replacementSessionId ?? replacement.sessionId, replacement.target, replacement.cwd, { isolation: replacement.isolation, workspaceCwd: this.cwd });
|
|
2811
3099
|
}
|
|
2812
3100
|
try {
|
|
2813
3101
|
await this.router.detachManagedSession(task.sessionId);
|
|
2814
3102
|
} catch (error) {
|
|
2815
|
-
|
|
3103
|
+
const healedReplacement = replacement !== void 0 && replacementSessionId !== void 0 && replacementSessionId !== replacement.sessionId ? { ...replacement, sessionId: replacementSessionId } : void 0;
|
|
3104
|
+
this.commitOwner(healedReplacement ? this.replaceTask(owner, healedReplacement, owner.activeTaskName) : owner);
|
|
2816
3105
|
this.router.forgetManagedSession(task.sessionId);
|
|
2817
|
-
await this.loadTask(task, `Task "${task.name}" could not be restored after close failed.`);
|
|
3106
|
+
const restored = await this.loadTask(task, `Task "${task.name}" could not be restored after close failed.`);
|
|
2818
3107
|
if (wasActive) {
|
|
2819
|
-
this.router.activateManagedSession(
|
|
3108
|
+
this.router.activateManagedSession(restored.sessionId, task.target, task.cwd, { isolation: task.isolation, workspaceCwd: this.cwd });
|
|
2820
3109
|
}
|
|
2821
3110
|
throw new Error(`Failed to close task "${task.name}".`, {
|
|
2822
3111
|
cause: error
|
|
@@ -2837,10 +3126,36 @@ var NamedSessionManager = class {
|
|
|
2837
3126
|
const task = this.findTask(owner, owner.activeTaskName);
|
|
2838
3127
|
if (!task || task.status !== "open")
|
|
2839
3128
|
return void 0;
|
|
3129
|
+
const timestamp = this.nextTimestamp(owner);
|
|
2840
3130
|
if (task.isolation === "worktree") {
|
|
2841
|
-
|
|
3131
|
+
if (this.isBusy(task.sessionId)) {
|
|
3132
|
+
throw new Error(`Task "${task.name}" is busy. Wait for the running prompt to finish (or cancel it), then try again.`);
|
|
3133
|
+
}
|
|
3134
|
+
const sessionId2 = await this.resetWorktreeSession(task);
|
|
3135
|
+
const updatedTask2 = {
|
|
3136
|
+
...task,
|
|
3137
|
+
sessionId: sessionId2,
|
|
3138
|
+
updatedAt: timestamp,
|
|
3139
|
+
lastSelectedAt: timestamp
|
|
3140
|
+
};
|
|
3141
|
+
const nextOwner2 = this.replaceTask(owner, updatedTask2, task.name);
|
|
3142
|
+
try {
|
|
3143
|
+
this.commitOwner(nextOwner2);
|
|
3144
|
+
} catch (error) {
|
|
3145
|
+
await this.router.detachManagedSession(sessionId2).catch(() => void 0);
|
|
3146
|
+
throw error;
|
|
3147
|
+
}
|
|
3148
|
+
this.router.activateManagedSession(sessionId2, updatedTask2.target, updatedTask2.cwd, { isolation: updatedTask2.isolation, workspaceCwd: this.cwd });
|
|
3149
|
+
this.router.forgetManagedSession(task.sessionId);
|
|
3150
|
+
this.repointSupersededSessionIds(task.sessionId, sessionId2);
|
|
3151
|
+
this.supersededSessionIds.delete(task.sessionId);
|
|
3152
|
+
return {
|
|
3153
|
+
name: task.name,
|
|
3154
|
+
previousSessionId: task.sessionId,
|
|
3155
|
+
sessionId: sessionId2,
|
|
3156
|
+
worktreeKept: true
|
|
3157
|
+
};
|
|
2842
3158
|
}
|
|
2843
|
-
const timestamp = this.nextTimestamp(owner);
|
|
2844
3159
|
const sessionId = await this.createSession(task.target, task.isolation, `Could not reset task "${task.name}".`);
|
|
2845
3160
|
const updatedTask = {
|
|
2846
3161
|
...task,
|
|
@@ -2855,12 +3170,15 @@ var NamedSessionManager = class {
|
|
|
2855
3170
|
await this.router.detachManagedSession(sessionId).catch(() => void 0);
|
|
2856
3171
|
throw error;
|
|
2857
3172
|
}
|
|
2858
|
-
this.router.activateManagedSession(sessionId, updatedTask.target, updatedTask.cwd);
|
|
3173
|
+
this.router.activateManagedSession(sessionId, updatedTask.target, updatedTask.cwd, { isolation: updatedTask.isolation, workspaceCwd: this.cwd });
|
|
2859
3174
|
this.router.forgetManagedSession(task.sessionId);
|
|
3175
|
+
this.repointSupersededSessionIds(task.sessionId, sessionId);
|
|
3176
|
+
this.supersededSessionIds.delete(task.sessionId);
|
|
2860
3177
|
return {
|
|
2861
3178
|
name: task.name,
|
|
2862
3179
|
previousSessionId: task.sessionId,
|
|
2863
|
-
sessionId
|
|
3180
|
+
sessionId,
|
|
3181
|
+
worktreeKept: false
|
|
2864
3182
|
};
|
|
2865
3183
|
});
|
|
2866
3184
|
}
|
|
@@ -2930,12 +3248,17 @@ var NamedSessionManager = class {
|
|
|
2930
3248
|
throw new Error("The selected Channel task is unavailable.");
|
|
2931
3249
|
}
|
|
2932
3250
|
const release = reserve?.(task.sessionId);
|
|
3251
|
+
let activeRelease = release;
|
|
2933
3252
|
try {
|
|
2934
|
-
await this.loadTask(task, `Could not load task "${task.name}". No replacement session was created.`);
|
|
2935
|
-
|
|
2936
|
-
|
|
3253
|
+
const result = await this.loadTask(task, `Could not load task "${task.name}". No replacement session was created.`);
|
|
3254
|
+
if (result.sessionId !== task.sessionId && reserve) {
|
|
3255
|
+
release?.();
|
|
3256
|
+
activeRelease = reserve(result.sessionId);
|
|
3257
|
+
}
|
|
3258
|
+
this.router.activateManagedSession(result.sessionId, task.target, task.cwd, { isolation: task.isolation, workspaceCwd: this.cwd });
|
|
3259
|
+
return result.sessionId;
|
|
2937
3260
|
} catch (error) {
|
|
2938
|
-
|
|
3261
|
+
activeRelease?.();
|
|
2939
3262
|
throw error;
|
|
2940
3263
|
}
|
|
2941
3264
|
}
|
|
@@ -2968,9 +3291,55 @@ var NamedSessionManager = class {
|
|
|
2968
3291
|
}
|
|
2969
3292
|
async loadTask(task, failureMessage) {
|
|
2970
3293
|
try {
|
|
2971
|
-
|
|
3294
|
+
const result = await this.router.loadManagedSession(task.sessionId, task.target, this.cwd, task.cwd, task.isolation);
|
|
3295
|
+
if (result.redirectedFrom !== void 0 && result.sessionId !== task.sessionId) {
|
|
3296
|
+
try {
|
|
3297
|
+
this.healSupersededTask(task, result.sessionId);
|
|
3298
|
+
} catch {
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
return result;
|
|
2972
3302
|
} catch (error) {
|
|
2973
|
-
throw new
|
|
3303
|
+
throw new NamedSessionTaskError(failureMessage, task.name, {
|
|
3304
|
+
cause: error
|
|
3305
|
+
});
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
/**
|
|
3309
|
+
* Point a task at its replacement session after a superseded redirect
|
|
3310
|
+
* healed the route. No-op when the registry entry already moved on (a
|
|
3311
|
+
* concurrent reset under the same owner lock cannot interleave, but a
|
|
3312
|
+
* stale in-memory snapshot could).
|
|
3313
|
+
*/
|
|
3314
|
+
healSupersededTask(task, sessionId) {
|
|
3315
|
+
const owner = this.getOwner(task.target);
|
|
3316
|
+
if (!owner)
|
|
3317
|
+
return;
|
|
3318
|
+
const current = this.findTask(owner, task.name);
|
|
3319
|
+
if (!current || current.sessionId !== task.sessionId)
|
|
3320
|
+
return;
|
|
3321
|
+
const timestamp = this.nextTimestamp(owner);
|
|
3322
|
+
this.commitOwner(this.replaceTask(owner, { ...current, sessionId, updatedAt: timestamp }, owner.activeTaskName));
|
|
3323
|
+
this.repointSupersededSessionIds(task.sessionId, sessionId);
|
|
3324
|
+
this.supersededSessionIds.set(task.sessionId, sessionId);
|
|
3325
|
+
}
|
|
3326
|
+
/**
|
|
3327
|
+
* Follow every id that still resolves to `oldSessionId` onto its
|
|
3328
|
+
* replacement, so a task superseded more than once stays reachable from the
|
|
3329
|
+
* oldest id a turn is bound to and the map does not grow once per reset.
|
|
3330
|
+
*/
|
|
3331
|
+
repointSupersededSessionIds(oldSessionId, newSessionId) {
|
|
3332
|
+
for (const boundSessionId of [...this.supersededSessionIds.keys()]) {
|
|
3333
|
+
if (this.supersededSessionIds.get(boundSessionId) === oldSessionId) {
|
|
3334
|
+
this.supersededSessionIds.set(boundSessionId, newSessionId);
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
async resetWorktreeSession(task) {
|
|
3339
|
+
try {
|
|
3340
|
+
return await this.router.replaceManagedWorktreeSession(task.sessionId, task.target, this.cwd, task.cwd);
|
|
3341
|
+
} catch (error) {
|
|
3342
|
+
throw new NamedSessionTaskError(`Could not reset task "${task.name}".`, task.name, { cause: error });
|
|
2974
3343
|
}
|
|
2975
3344
|
}
|
|
2976
3345
|
async createSession(target, isolation, failureMessage) {
|
|
@@ -4049,8 +4418,8 @@ var ChannelBase = class {
|
|
|
4049
4418
|
bridgeToolCallListener = /* @__PURE__ */ __name((event) => {
|
|
4050
4419
|
this.dispatchToolCall(event);
|
|
4051
4420
|
}, "bridgeToolCallListener");
|
|
4052
|
-
bridgeBackgroundResponseListener = /* @__PURE__ */ __name((sessionId, text) => {
|
|
4053
|
-
void this.dispatchBackgroundResponse(sessionId, text).catch((err) => {
|
|
4421
|
+
bridgeBackgroundResponseListener = /* @__PURE__ */ __name((sessionId, text, context) => {
|
|
4422
|
+
void this.dispatchBackgroundResponse(sessionId, text, context).catch((err) => {
|
|
4054
4423
|
process.stderr.write(`[${this.name}] background response delivery failed for session ${sanitizeLogText(sessionId, 128)}: ${this.lifecycleError(err)}
|
|
4055
4424
|
`);
|
|
4056
4425
|
});
|
|
@@ -4058,6 +4427,9 @@ var ChannelBase = class {
|
|
|
4058
4427
|
bridgeSessionDiedListener = /* @__PURE__ */ __name((event) => {
|
|
4059
4428
|
this.onSessionDied(event.sessionId);
|
|
4060
4429
|
}, "bridgeSessionDiedListener");
|
|
4430
|
+
bridgeDisconnectedListener = /* @__PURE__ */ __name(() => {
|
|
4431
|
+
this.onBridgeDisconnected();
|
|
4432
|
+
}, "bridgeDisconnectedListener");
|
|
4061
4433
|
bridgePermissionRequestListener = /* @__PURE__ */ __name((event) => {
|
|
4062
4434
|
void this.dispatchPermissionRequest(event).catch((err) => {
|
|
4063
4435
|
process.stderr.write(`[${this.name}] permission relay failed for request ${sanitizeLogText(event.requestId, 128)}: ${this.lifecycleError(err)}
|
|
@@ -4098,11 +4470,19 @@ var ChannelBase = class {
|
|
|
4098
4470
|
}
|
|
4099
4471
|
this.onToolCall(chatId, event);
|
|
4100
4472
|
}
|
|
4101
|
-
async dispatchBackgroundResponse(sessionId, text) {
|
|
4102
|
-
|
|
4103
|
-
|
|
4473
|
+
async dispatchBackgroundResponse(sessionId, text, _context) {
|
|
4474
|
+
if (text.trim().length === 0)
|
|
4475
|
+
return;
|
|
4476
|
+
const delivery = await this.resolveBackgroundResponseDelivery(sessionId);
|
|
4477
|
+
if (!delivery || this.router.getTarget(sessionId) !== delivery.target) {
|
|
4104
4478
|
return;
|
|
4105
4479
|
}
|
|
4480
|
+
await this.deliverBackgroundResponseToTarget(sessionId, text, delivery);
|
|
4481
|
+
}
|
|
4482
|
+
async resolveBackgroundResponseDelivery(sessionId) {
|
|
4483
|
+
let target = this.router.getTarget(sessionId);
|
|
4484
|
+
if (!target || target.channelName !== this.name)
|
|
4485
|
+
return void 0;
|
|
4106
4486
|
let sourceLabel;
|
|
4107
4487
|
if (this.namedSessions) {
|
|
4108
4488
|
const presentation = await this.namedSessions.resolvePresentation(sessionId);
|
|
@@ -4114,6 +4494,10 @@ var ChannelBase = class {
|
|
|
4114
4494
|
target = currentTarget;
|
|
4115
4495
|
sourceLabel = this.createSourceLabel(presentation, target);
|
|
4116
4496
|
}
|
|
4497
|
+
return { target, sourceLabel };
|
|
4498
|
+
}
|
|
4499
|
+
async deliverBackgroundResponseToTarget(sessionId, text, delivery) {
|
|
4500
|
+
const { target, sourceLabel } = delivery;
|
|
4117
4501
|
if (this.supportsProactiveSend() && this.supportsProactiveTarget(target)) {
|
|
4118
4502
|
if (sourceLabel) {
|
|
4119
4503
|
await this.pushProactive(target, text, sourceLabel);
|
|
@@ -5399,6 +5783,7 @@ ${promptText}` : promptText;
|
|
|
5399
5783
|
]);
|
|
5400
5784
|
if (!cancelled) {
|
|
5401
5785
|
this.cancelBtw(sessionId);
|
|
5786
|
+
this.onSessionRetiring(sessionId);
|
|
5402
5787
|
this.router.removeSessionId(sessionId);
|
|
5403
5788
|
this.instructedSessions.delete(sessionId);
|
|
5404
5789
|
this.unattendedMemorySessions.delete(sessionId);
|
|
@@ -5527,10 +5912,21 @@ ${promptText}` : promptText;
|
|
|
5527
5912
|
this.unattendedMemorySessions.delete(sessionId);
|
|
5528
5913
|
this.removePendingPermissionsForSession(sessionId);
|
|
5529
5914
|
}
|
|
5915
|
+
/**
|
|
5916
|
+
* Called when the standalone ACP bridge process exits. Its in-flight turns
|
|
5917
|
+
* never settle, but crash recovery restores the sessions on a fresh bridge,
|
|
5918
|
+
* so overrides must clear only turn-scoped transient state (never session
|
|
5919
|
+
* routing) and must not fabricate terminal outcomes for interrupted turns.
|
|
5920
|
+
*/
|
|
5921
|
+
onBridgeDisconnected() {
|
|
5922
|
+
}
|
|
5923
|
+
onSessionRetiring(_sessionId) {
|
|
5924
|
+
}
|
|
5530
5925
|
attachBridgeEvents(bridge) {
|
|
5531
5926
|
bridge.on("toolCall", this.bridgeToolCallListener);
|
|
5532
5927
|
bridge.on("backgroundResponse", this.bridgeBackgroundResponseListener);
|
|
5533
5928
|
bridge.on("sessionDied", this.bridgeSessionDiedListener);
|
|
5929
|
+
bridge.on("disconnected", this.bridgeDisconnectedListener);
|
|
5534
5930
|
bridge.on("permissionRequest", this.bridgePermissionRequestListener);
|
|
5535
5931
|
bridge.on("permissionResolved", this.bridgePermissionResolvedListener);
|
|
5536
5932
|
}
|
|
@@ -5538,6 +5934,7 @@ ${promptText}` : promptText;
|
|
|
5538
5934
|
bridge.off("toolCall", this.bridgeToolCallListener);
|
|
5539
5935
|
bridge.off("backgroundResponse", this.bridgeBackgroundResponseListener);
|
|
5540
5936
|
bridge.off("sessionDied", this.bridgeSessionDiedListener);
|
|
5937
|
+
bridge.off("disconnected", this.bridgeDisconnectedListener);
|
|
5541
5938
|
bridge.off("permissionRequest", this.bridgePermissionRequestListener);
|
|
5542
5939
|
bridge.off("permissionResolved", this.bridgePermissionResolvedListener);
|
|
5543
5940
|
}
|
|
@@ -5975,6 +6372,21 @@ ${requestList}`);
|
|
|
5975
6372
|
binding.released = true;
|
|
5976
6373
|
this.releaseQueuedTurn(binding.sessionId);
|
|
5977
6374
|
}
|
|
6375
|
+
/**
|
|
6376
|
+
* Follow a task onto the session its reload healed to (a superseded
|
|
6377
|
+
* redirect). The queue reservation and the staleness generation are keyed
|
|
6378
|
+
* by session id, so both must move with the binding: leaving them behind
|
|
6379
|
+
* keeps the stale id "busy" forever and drops the turn on a generation the
|
|
6380
|
+
* replacement never had.
|
|
6381
|
+
*/
|
|
6382
|
+
moveNamedTurnBinding(binding, sessionId) {
|
|
6383
|
+
if (binding.sessionId !== null) {
|
|
6384
|
+
this.releaseQueuedTurn(binding.sessionId);
|
|
6385
|
+
}
|
|
6386
|
+
binding.sessionId = sessionId;
|
|
6387
|
+
binding.generation = this.sessionGenerations.get(sessionId) ?? 0;
|
|
6388
|
+
this.reserveQueuedTurn(sessionId);
|
|
6389
|
+
}
|
|
5978
6390
|
finishNamedTurnBinding(envelope) {
|
|
5979
6391
|
const binding = this.namedTurnBindings.get(envelope);
|
|
5980
6392
|
if (!binding)
|
|
@@ -6030,12 +6442,51 @@ ${requestList}`);
|
|
|
6030
6442
|
return true;
|
|
6031
6443
|
}
|
|
6032
6444
|
}
|
|
6445
|
+
/**
|
|
6446
|
+
* The actionable recovery message for a worktree task whose ownership state
|
|
6447
|
+
* the daemon refused to restore. Both codes come from the load/resume route
|
|
6448
|
+
* — the reset route resumes an interrupted transfer itself and reports a
|
|
6449
|
+
* broken marker as invalid state — so they surface on selection and on a
|
|
6450
|
+
* message, wrapped in the manager's generic load failure.
|
|
6451
|
+
*
|
|
6452
|
+
* Clearing always acts on the *selected* task, so pointing the user at a
|
|
6453
|
+
* clear is only safe when the task that failed is the selected one. Aimed at
|
|
6454
|
+
* any other task it would run a full ownership transfer against a healthy
|
|
6455
|
+
* one and destroy that conversation, so the alternative points at the close
|
|
6456
|
+
* that works on the broken task without loading it. Both name that task.
|
|
6457
|
+
*/
|
|
6458
|
+
async worktreeRecoveryMessage(envelope, error) {
|
|
6459
|
+
const code = readDaemonHttpErrorCode(error);
|
|
6460
|
+
if (code !== "worktree_reset_interrupted" && code !== "worktree_marker_missing") {
|
|
6461
|
+
return void 0;
|
|
6462
|
+
}
|
|
6463
|
+
const interrupted = code === "worktree_reset_interrupted";
|
|
6464
|
+
const failedTaskName = error instanceof NamedSessionTaskError ? error.taskName : void 0;
|
|
6465
|
+
const safeTaskName = failedTaskName === void 0 ? void 0 : sanitizeDisplayText(failedTaskName, 32);
|
|
6466
|
+
const subject = safeTaskName === void 0 ? "The task" : `Task "${safeTaskName}"`;
|
|
6467
|
+
const problem = interrupted ? "was interrupted while being reset" : "cannot verify its worktree because its ownership marker is missing";
|
|
6468
|
+
if (safeTaskName !== void 0 && failedTaskName === await this.selectedTaskName(envelope)) {
|
|
6469
|
+
return `${subject} ${problem}. Its files were not changed. ${interrupted ? "Clear the task again to finish the reset." : "Clear the task to restart it in the same worktree, or close it."}`;
|
|
6470
|
+
}
|
|
6471
|
+
const remedy = safeTaskName === void 0 ? "select this task first or close it" : `select this task first or close it with ${this.prefixedCommand(`/session close ${safeTaskName}`)}`;
|
|
6472
|
+
return `${subject} ${problem}. Its files were not changed. Clearing now would reset the selected task instead, so ${remedy}.`;
|
|
6473
|
+
}
|
|
6474
|
+
async selectedTaskName(envelope) {
|
|
6475
|
+
const namedSessions = this.namedSessions;
|
|
6476
|
+
if (!namedSessions)
|
|
6477
|
+
return void 0;
|
|
6478
|
+
try {
|
|
6479
|
+
return (await namedSessions.current(this.namedSessionOwner(envelope)))?.name;
|
|
6480
|
+
} catch {
|
|
6481
|
+
return void 0;
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6033
6484
|
async sendNamedSessionError(envelope, error) {
|
|
6034
6485
|
if (error instanceof Error && error.cause !== void 0) {
|
|
6035
6486
|
process.stderr.write(`[${sanitizeLogText(this.name, 64)}] named-session operation failed: ${this.lifecycleError(error)} | cause: ${this.lifecycleError(error.cause)}
|
|
6036
6487
|
`);
|
|
6037
6488
|
}
|
|
6038
|
-
const message = error instanceof Error ? sanitizeDisplayText(error.message, 500) : "Named-session operation failed.";
|
|
6489
|
+
const message = await this.worktreeRecoveryMessage(envelope, error) ?? (error instanceof Error ? sanitizeDisplayText(error.message, 500) : "Named-session operation failed.");
|
|
6039
6490
|
await this.sendThreadMessage(envelope.chatId, envelope.threadId, message || "Named-session operation failed.");
|
|
6040
6491
|
}
|
|
6041
6492
|
async handleNamedSessionsCommand(envelope, args) {
|
|
@@ -6080,7 +6531,7 @@ ${requestList}`);
|
|
|
6080
6531
|
}
|
|
6081
6532
|
case "new": {
|
|
6082
6533
|
const isolation = parts.length === 2 && parts[1] === "--worktree" ? "worktree" : "shared";
|
|
6083
|
-
if (isolation === "shared" && parts.length !== 1 || isolation === "worktree" && parts.length !== 2) {
|
|
6534
|
+
if (isolation === "shared" && parts.length !== 1 || isolation === "worktree" && parts.length !== 2 || parts[0]?.startsWith("-")) {
|
|
6084
6535
|
break;
|
|
6085
6536
|
}
|
|
6086
6537
|
const created = await namedSessions.create(owner, parts[0], isolation);
|
|
@@ -6099,8 +6550,10 @@ ${requestList}`);
|
|
|
6099
6550
|
break;
|
|
6100
6551
|
const closing = await namedSessions.lookup(owner, parts[0]);
|
|
6101
6552
|
const result = await namedSessions.close(owner, parts[0]);
|
|
6102
|
-
if (closing)
|
|
6553
|
+
if (closing) {
|
|
6103
6554
|
this.cancelBtw(closing.sessionId);
|
|
6555
|
+
this.onSessionRetiring(closing.sessionId);
|
|
6556
|
+
}
|
|
6104
6557
|
await this.sendThreadMessage(envelope.chatId, envelope.threadId, result.active ? `Closed task "${result.closed.name}". Selected "${result.active.name}".` : `Closed task "${result.closed.name}". No task is selected.`);
|
|
6105
6558
|
return true;
|
|
6106
6559
|
}
|
|
@@ -6139,13 +6592,27 @@ ${requestList}`);
|
|
|
6139
6592
|
registerSharedCommands() {
|
|
6140
6593
|
const doClear = /* @__PURE__ */ __name(async (envelope) => {
|
|
6141
6594
|
let resetTaskName;
|
|
6595
|
+
let resetWorktreeKept = false;
|
|
6142
6596
|
let removedIds;
|
|
6597
|
+
const retiringSessionId = this.namedSessions ? void 0 : this.router.getSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
|
|
6598
|
+
if (retiringSessionId)
|
|
6599
|
+
this.onSessionRetiring(retiringSessionId);
|
|
6143
6600
|
if (this.namedSessions) {
|
|
6144
6601
|
try {
|
|
6145
6602
|
const reset = await this.namedSessions.reset(this.namedSessionOwner(envelope));
|
|
6146
6603
|
resetTaskName = reset?.name;
|
|
6604
|
+
resetWorktreeKept = reset?.worktreeKept ?? false;
|
|
6147
6605
|
removedIds = reset ? [reset.previousSessionId] : [];
|
|
6148
6606
|
} catch (error) {
|
|
6607
|
+
const code = readDaemonHttpErrorCode(error);
|
|
6608
|
+
if (code !== void 0) {
|
|
6609
|
+
process.stderr.write(`[${sanitizeLogText(this.name, 64)}] worktree reset failed (${sanitizeLogText(code, 64)}): ${this.lifecycleError(error)}
|
|
6610
|
+
`);
|
|
6611
|
+
}
|
|
6612
|
+
if (code === "worktree_reset_active") {
|
|
6613
|
+
await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Task is busy. Wait for the running prompt to finish (or cancel it), then try again.");
|
|
6614
|
+
return;
|
|
6615
|
+
}
|
|
6149
6616
|
await this.sendNamedSessionError(envelope, error);
|
|
6150
6617
|
return;
|
|
6151
6618
|
}
|
|
@@ -6155,6 +6622,8 @@ ${requestList}`);
|
|
|
6155
6622
|
this.clearPendingGroupHistory(envelope);
|
|
6156
6623
|
if (removedIds.length > 0) {
|
|
6157
6624
|
for (const id of removedIds) {
|
|
6625
|
+
if (id !== retiringSessionId)
|
|
6626
|
+
this.onSessionRetiring(id);
|
|
6158
6627
|
this.cancelBtw(id);
|
|
6159
6628
|
if (this.isSharedSession(envelope)) {
|
|
6160
6629
|
const who = sanitizeSenderName(envelope.senderName || envelope.senderId || "unknown");
|
|
@@ -6198,7 +6667,7 @@ ${requestList}`);
|
|
|
6198
6667
|
}
|
|
6199
6668
|
this.discardRetiredSession(this.bridge, id, "cleared");
|
|
6200
6669
|
}
|
|
6201
|
-
await this.sendThreadMessage(envelope.chatId, envelope.threadId, resetTaskName ? `Task "${resetTaskName}" reset with a fresh conversation.` : "Session cleared. The next message starts a fresh conversation.");
|
|
6670
|
+
await this.sendThreadMessage(envelope.chatId, envelope.threadId, resetTaskName ? resetWorktreeKept ? `Task "${resetTaskName}" reset with a fresh conversation; its worktree and files were kept.` : `Task "${resetTaskName}" reset with a fresh conversation.` : "Session cleared. The next message starts a fresh conversation.");
|
|
6202
6671
|
} else {
|
|
6203
6672
|
await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No active session to clear.");
|
|
6204
6673
|
}
|
|
@@ -7723,8 +8192,10 @@ ${text}`;
|
|
|
7723
8192
|
return;
|
|
7724
8193
|
}
|
|
7725
8194
|
try {
|
|
7726
|
-
|
|
7727
|
-
sessionId
|
|
8195
|
+
sessionId = await this.namedSessions.resumeReserved(this.namedSessionOwner(envelope), namedTurn.sessionId);
|
|
8196
|
+
if (sessionId && sessionId !== namedTurn.sessionId) {
|
|
8197
|
+
this.moveNamedTurnBinding(namedTurn, sessionId);
|
|
8198
|
+
}
|
|
7728
8199
|
} catch (error) {
|
|
7729
8200
|
await this.sendNamedSessionError(envelope, error);
|
|
7730
8201
|
return;
|
|
@@ -8437,6 +8908,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
8437
8908
|
activePrompts = /* @__PURE__ */ new Set();
|
|
8438
8909
|
activePromptControllers = /* @__PURE__ */ new Map();
|
|
8439
8910
|
availableCommandsBySession = /* @__PURE__ */ new Map();
|
|
8911
|
+
toolCallKindsBySession = /* @__PURE__ */ new Map();
|
|
8440
8912
|
turnBarriers = /* @__PURE__ */ new Map();
|
|
8441
8913
|
channelLoopToolHandlers = [];
|
|
8442
8914
|
channelLoopDisabledSessions = /* @__PURE__ */ new Set();
|
|
@@ -8543,6 +9015,38 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
8543
9015
|
}
|
|
8544
9016
|
return session.sessionId;
|
|
8545
9017
|
}
|
|
9018
|
+
/**
|
|
9019
|
+
* Transfer a worktree session's checkout ownership to a fresh replacement
|
|
9020
|
+
* session (daemon `session_worktree_reset_v1`). The returned id is the
|
|
9021
|
+
* replacement's; the superseded session's clients stay bound to it (and
|
|
9022
|
+
* are forgotten by the caller). Gated on the capability flag so a daemon
|
|
9023
|
+
* without reset support fails before any session is created.
|
|
9024
|
+
*/
|
|
9025
|
+
async resetWorktreeSession(sessionId, cwd, options, bindingToken) {
|
|
9026
|
+
if (!this.options.sessionWorktreeReset) {
|
|
9027
|
+
throw new Error("The daemon does not support worktree reset for Channel tasks.");
|
|
9028
|
+
}
|
|
9029
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
9030
|
+
const session = await this.options.sessionFactory({
|
|
9031
|
+
workspaceCwd: cwd || this.options.cwd,
|
|
9032
|
+
modelServiceId: this.options.modelServiceId,
|
|
9033
|
+
sessionScope: this.options.sessionScope ?? "thread",
|
|
9034
|
+
...options?.approvalMode ? { approvalMode: options.approvalMode } : {},
|
|
9035
|
+
...options?.sourceId ? { sourceId: options.sourceId } : {},
|
|
9036
|
+
worktreeReset: { sessionId }
|
|
9037
|
+
});
|
|
9038
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) {
|
|
9039
|
+
await this.rejectStaleSession(session);
|
|
9040
|
+
}
|
|
9041
|
+
this.attachSession(session, bindingToken);
|
|
9042
|
+
if (options?.enableChannelLoops === false) {
|
|
9043
|
+
this.channelLoopDisabledSessions.add(session.sessionId);
|
|
9044
|
+
void this.reconcileChannelLoopMcpForSession(session.sessionId);
|
|
9045
|
+
} else {
|
|
9046
|
+
await this.reconcileChannelLoopMcpForSession(session.sessionId);
|
|
9047
|
+
}
|
|
9048
|
+
return session.sessionId;
|
|
9049
|
+
}
|
|
8546
9050
|
registerChannelLoopToolHandler(handler) {
|
|
8547
9051
|
if (!this.channelLoopToolHandlers.includes(handler)) {
|
|
8548
9052
|
this.channelLoopToolHandlers.push(handler);
|
|
@@ -8924,8 +9428,11 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
8924
9428
|
}
|
|
8925
9429
|
const text = getTextContent(update["content"]);
|
|
8926
9430
|
if (meta?.["qwenDiscreteMessage"] === true) {
|
|
8927
|
-
if (meta["source"] === "background_notification_response" && meta["rewritten"] !== true
|
|
8928
|
-
|
|
9431
|
+
if (meta["source"] === "background_notification_response" && meta["rewritten"] !== true) {
|
|
9432
|
+
const context = parseBackgroundResponseContext(meta["backgroundTask"]);
|
|
9433
|
+
if (text || context?.turnComplete) {
|
|
9434
|
+
this.emit("backgroundResponse", sessionId, text ?? "", context);
|
|
9435
|
+
}
|
|
8929
9436
|
} else if (meta["source"] === "vision_bridge_notice" && text) {
|
|
8930
9437
|
this.emit("textChunk", sessionId, text);
|
|
8931
9438
|
}
|
|
@@ -8946,15 +9453,23 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
8946
9453
|
case "tool_call":
|
|
8947
9454
|
case "tool_call_update": {
|
|
8948
9455
|
const toolCallId = getString(update["toolCallId"]);
|
|
8949
|
-
const
|
|
9456
|
+
const explicitKind = getString(update["kind"]);
|
|
8950
9457
|
const meta = isRecord3(update["_meta"]) ? update["_meta"] : void 0;
|
|
8951
|
-
if (!
|
|
9458
|
+
if (!explicitKind && toolCallId && getString(update["status"]) === "in_progress" && (meta?.["shellProgress"] !== void 0 || meta?.["subagentProgress"] === true)) {
|
|
8952
9459
|
break;
|
|
8953
9460
|
}
|
|
9461
|
+
let sessionKinds = this.toolCallKindsBySession.get(sessionId);
|
|
9462
|
+
const kind = explicitKind || sessionKinds?.get(toolCallId ?? "");
|
|
8954
9463
|
if (!toolCallId || !kind) {
|
|
8955
9464
|
this.emitProtocolError(`Malformed daemon ${type} event`, update);
|
|
8956
9465
|
break;
|
|
8957
9466
|
}
|
|
9467
|
+
if (type === "tool_call" || explicitKind) {
|
|
9468
|
+
const kinds = sessionKinds ?? /* @__PURE__ */ new Map();
|
|
9469
|
+
kinds.set(toolCallId, kind);
|
|
9470
|
+
this.toolCallKindsBySession.set(sessionId, kinds);
|
|
9471
|
+
sessionKinds = kinds;
|
|
9472
|
+
}
|
|
8958
9473
|
const event = {
|
|
8959
9474
|
sessionId,
|
|
8960
9475
|
toolCallId,
|
|
@@ -8967,6 +9482,12 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
8967
9482
|
this.emitResponseBoundary(sessionId);
|
|
8968
9483
|
}
|
|
8969
9484
|
this.emit("toolCall", event);
|
|
9485
|
+
if (event.status === "completed" || event.status === "failed") {
|
|
9486
|
+
sessionKinds?.delete(toolCallId);
|
|
9487
|
+
if (sessionKinds?.size === 0) {
|
|
9488
|
+
this.toolCallKindsBySession.delete(sessionId);
|
|
9489
|
+
}
|
|
9490
|
+
}
|
|
8970
9491
|
break;
|
|
8971
9492
|
}
|
|
8972
9493
|
case "plan": {
|
|
@@ -9094,6 +9615,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
9094
9615
|
this.abortActivePrompts(sessionId);
|
|
9095
9616
|
this.activePrompts.delete(sessionId);
|
|
9096
9617
|
this.availableCommandsBySession.delete(sessionId);
|
|
9618
|
+
this.toolCallKindsBySession.delete(sessionId);
|
|
9097
9619
|
if (this.latestAvailableCommandsSessionId === sessionId) {
|
|
9098
9620
|
this.latestAvailableCommandsSessionId = Array.from(this.availableCommandsBySession.keys()).at(-1);
|
|
9099
9621
|
}
|