@qwen-code/qwen-code 0.23.1-preview.2 → 0.23.2-nightly.20260909.2e212144d3
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/README.md +35 -15
- 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/auth.md +1 -1
- package/bundled/qc-helper/docs/configuration/model-providers.md +66 -16
- package/bundled/qc-helper/docs/configuration/settings.md +50 -0
- package/bundled/qc-helper/docs/conversations-recovery.md +102 -0
- package/bundled/qc-helper/docs/features/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +1 -1
- package/bundled/qc-helper/docs/features/channels/github.md +1 -9
- package/bundled/qc-helper/docs/features/channels/overview.md +27 -52
- package/bundled/qc-helper/docs/features/channels/qqbot.md +1 -2
- package/bundled/qc-helper/docs/features/commands.md +79 -17
- package/bundled/qc-helper/docs/features/computer-use.md +9 -7
- package/bundled/qc-helper/docs/features/cross-session-protocol.md +291 -0
- package/bundled/qc-helper/docs/features/followup-suggestions.md +2 -2
- package/bundled/qc-helper/docs/features/goals.md +17 -3
- package/bundled/qc-helper/docs/features/sub-agents.md +8 -0
- package/bundled/qc-helper/docs/qwen-serve.md +80 -48
- package/chunks/{MaxSizedBox-IYIQ43IZ.js → MaxSizedBox-ZBGWYJZW.js} +29 -28
- package/chunks/{StandaloneSessionPicker-AWB2OHX6.js → StandaloneSessionPicker-NR5ACIJZ.js} +48 -47
- package/chunks/{acp-startup-profiler-BAL4LJTN.js → acp-startup-profiler-KEU6VAYR.js} +2 -2
- package/chunks/{acpAgent-ZC57OLS4.js → acpAgent-DM6XRCDQ.js} +361 -210
- package/chunks/{agent-GEBPAEJS.js → agent-EF3IIYE3.js} +20 -20
- package/chunks/{agent-headless-63ZEYAJK.js → agent-headless-5J2KFYR4.js} +20 -20
- package/chunks/{anthropicContentGenerator-6XDHXIII.js → anthropicContentGenerator-VIW2FG7G.js} +32 -9
- package/chunks/{artifact-tool-P52OKKEF.js → artifact-tool-G5LHNECG.js} +1 -1
- package/chunks/{askUserQuestion-3KAYLLMM.js → askUserQuestion-R3TXY77M.js} +1 -1
- package/chunks/{bridge-MHWO5I5T.js → bridge-LEMQM6QE.js} +32 -31
- package/chunks/{channel-management-service-NFRZXQFO.js → channel-management-service-TGF6XFXT.js} +4 -4
- package/chunks/{channel-settings-store-T7PMIHKC.js → channel-settings-store-FV365JSF.js} +40 -39
- package/chunks/{channel-worker-group-O2BWK5F7.js → channel-worker-group-SQ5FRWOH.js} +7 -7
- package/chunks/{channel-worker-manager-4WP7VJOD.js → channel-worker-manager-TU4ZNWOE.js} +7 -7
- package/chunks/{channel-worker-supervisor-CCUXD6J5.js → channel-worker-supervisor-EMITFMCP.js} +4 -4
- package/chunks/{chunk-3SH53ANB.js → chunk-22GORRNY.js} +12 -0
- package/chunks/{chunk-OFB36ZBA.js → chunk-2HYOOFDS.js} +10 -7
- package/chunks/chunk-2Z3T52OC.js +82 -0
- package/chunks/{chunk-LYHYXJJ3.js → chunk-34VPADLG.js} +3 -3
- package/chunks/{chunk-C7M445SS.js → chunk-3A2IMUDH.js} +14 -2
- package/chunks/{chunk-P5Z7VD23.js → chunk-3O77M472.js} +294 -87
- package/chunks/{chunk-4OCYWXKF.js → chunk-43EUMPKQ.js} +3 -3
- package/chunks/{chunk-W4LL5RZO.js → chunk-4ALNJDHL.js} +52 -13
- package/chunks/{chunk-VMFPZXRT.js → chunk-4DIMJKWU.js} +64 -43
- package/chunks/{chunk-ZRVFHLLK.js → chunk-5DQ4YTIZ.js} +1 -1
- package/chunks/{chunk-VYCJITND.js → chunk-5HV2HPO7.js} +1 -1
- package/chunks/{chunk-22QOQKG4.js → chunk-5WBA3DEF.js} +1 -1
- package/chunks/{chunk-3K65MUKD.js → chunk-65I7S4Z3.js} +2 -1
- package/chunks/{chunk-I7UNCY24.js → chunk-6GAYNM3F.js} +3 -3
- package/chunks/{chunk-2C3XDBGL.js → chunk-6S7YYUUH.js} +4 -4
- package/chunks/{chunk-Y3C5COGI.js → chunk-6VIATHL7.js} +1 -1
- package/chunks/{chunk-XNC2TCUO.js → chunk-76I36BEM.js} +4 -4
- package/chunks/{chunk-B54PFQS5.js → chunk-7CLLH5TI.js} +1 -1
- package/chunks/{chunk-RGAQDQ3Z.js → chunk-7IDZFJAV.js} +18 -9
- package/chunks/{chunk-5Z4FCEPY.js → chunk-7K4GGN3D.js} +606 -109
- package/chunks/{chunk-WLZRMF3C.js → chunk-7KZVXJ4U.js} +353 -11
- package/chunks/{chunk-REDVV5NC.js → chunk-7WCJEY3A.js} +7 -7
- package/chunks/{chunk-I67KJGM6.js → chunk-A7QZIGRB.js} +3 -3
- package/chunks/{chunk-SHX2HIE7.js → chunk-ATBLEXXV.js} +7 -2
- package/chunks/{chunk-RH344FKI.js → chunk-AUTUFD5X.js} +1 -1
- package/chunks/chunk-AXMWHKXA.js +42 -0
- package/chunks/{chunk-WFXD5OZH.js → chunk-AXWTG6R7.js} +2 -5
- package/chunks/{chunk-TSLRORQR.js → chunk-BDAVT6K2.js} +1809 -1588
- package/chunks/{chunk-HWZOOSEB.js → chunk-BDP3NTWD.js} +3 -3
- package/chunks/{chunk-RD3VPM4E.js → chunk-BZUHZCUO.js} +2 -2
- package/chunks/{chunk-HPE4LEWX.js → chunk-C24ZDDNY.js} +1 -1
- package/chunks/{chunk-R7TKFIQO.js → chunk-CALNF3Z3.js} +1 -1
- package/chunks/{chunk-RPFJJ33Z.js → chunk-CALTQWTZ.js} +1 -1
- package/chunks/{chunk-BF3RUIVP.js → chunk-CH2YDT6X.js} +36 -38
- package/chunks/{chunk-LD53HMPV.js → chunk-CRZBDVP2.js} +1 -0
- package/chunks/{chunk-GEV66YGE.js → chunk-D6AGS266.js} +1 -1
- package/chunks/{chunk-EPZWBYQI.js → chunk-D7DFZAK2.js} +19 -11
- package/chunks/{chunk-5V4B3EWA.js → chunk-DARWOZY6.js} +1 -1
- package/chunks/{chunk-XX4MBBFW.js → chunk-DGNRLJ6S.js} +4 -4
- package/chunks/{chunk-UTVIIA7N.js → chunk-DVOCOIS5.js} +1 -1
- package/chunks/{chunk-RQNAO42A.js → chunk-E4LXNQAK.js} +1 -1
- package/chunks/{chunk-EGRFCIXD.js → chunk-EATP5QCN.js} +84 -25
- package/chunks/{chunk-3RMVM33U.js → chunk-EDSU3VUG.js} +12 -5
- package/chunks/{chunk-733KQL63.js → chunk-EE5ZD4XU.js} +3 -3
- package/chunks/{chunk-QQGAR64U.js → chunk-EN3Q2S3J.js} +4 -4
- package/chunks/{chunk-PLUAIHZO.js → chunk-EOLGAQ25.js} +17 -16
- package/chunks/{chunk-37SOBIA3.js → chunk-ERXNTINK.js} +1 -1
- package/chunks/{chunk-L36LLVA5.js → chunk-EYCW6UF2.js} +7 -7
- package/chunks/{chunk-ZELCTN6Y.js → chunk-F23YN37B.js} +10 -0
- package/chunks/{chunk-FPGTNKCP.js → chunk-F3M6P6IQ.js} +199 -1
- package/chunks/{chunk-B44JBZBB.js → chunk-F4SAL7WM.js} +91 -3
- package/chunks/{chunk-F47DITLZ.js → chunk-FAWTMDX7.js} +14 -0
- package/chunks/{chunk-SI6Q52UI.js → chunk-FEEVHJOR.js} +3 -3
- package/chunks/{chunk-75UQFGFE.js → chunk-FN4KHWCL.js} +1 -1
- package/chunks/{chunk-WQBR7LN5.js → chunk-FRS3P7MQ.js} +15 -2
- package/chunks/{chunk-5JLQWQK6.js → chunk-FV4DM2M4.js} +2 -2
- package/chunks/{chunk-Z6DDPSGJ.js → chunk-GNY7B3CA.js} +1 -1
- package/chunks/{chunk-FDOGGKAA.js → chunk-GSFV5RQW.js} +2 -0
- package/chunks/{chunk-XBVNNDPK.js → chunk-GSYD7MYP.js} +8 -3
- package/chunks/{chunk-ERMAXPXA.js → chunk-HIXUUCGY.js} +187 -12
- package/chunks/{chunk-EJNYBDYC.js → chunk-HNLMYDQE.js} +1 -1
- package/chunks/{chunk-3K456UJF.js → chunk-HSO6D4KX.js} +93 -28
- package/chunks/{chunk-ANVC5CSK.js → chunk-HUJJFSMO.js} +10 -10
- package/chunks/{chunk-C4NXRR7T.js → chunk-HW4MRP4V.js} +2 -2
- package/chunks/{chunk-PMGWY6ZP.js → chunk-HWLLUDIA.js} +113 -18
- package/chunks/{chunk-RCUWMVN3.js → chunk-HZ2HUXX7.js} +1 -1
- package/chunks/{chunk-7PMKXGRP.js → chunk-IKK6NNS6.js} +91 -31
- package/chunks/{chunk-IMWCUWQT.js → chunk-J3TJH52D.js} +1 -1
- package/chunks/{chunk-BNWIX6BM.js → chunk-JFAGT5YG.js} +3 -3
- package/chunks/{chunk-RSU3I6UL.js → chunk-JGTMTJSQ.js} +1 -1
- package/chunks/{chunk-LTCI6ZOJ.js → chunk-JYGIJA4W.js} +1 -1
- package/chunks/{chunk-537SQ2AI.js → chunk-KECCLCXM.js} +146 -24
- package/chunks/{chunk-KAZWXVI3.js → chunk-KEPC5BOL.js} +5 -5
- package/chunks/{chunk-HZS3JRQW.js → chunk-L5VHJYHH.js} +40 -2
- package/chunks/{chunk-KTLT7VCX.js → chunk-LKBOBUA2.js} +2 -2
- package/chunks/{chunk-TDHVOZ65.js → chunk-LOBKNYPR.js} +2 -2
- package/chunks/{chunk-QW7BUOSI.js → chunk-LOVGQ3HZ.js} +26 -9
- package/chunks/{chunk-5FYGZ7E3.js → chunk-MUF4UGPB.js} +2 -2
- package/chunks/chunk-N3Z6Q7KC.js +384 -0
- package/chunks/{chunk-JOV46WGX.js → chunk-NB3NDQQK.js} +1 -1
- package/chunks/chunk-NFXXBWSE.js +463 -0
- package/chunks/chunk-NOO4QFXM.js +171 -0
- package/chunks/{chunk-PQSCGZT2.js → chunk-NPKCVSXX.js} +26 -2
- package/chunks/{chunk-FXYNIZPW.js → chunk-NV4YYXFT.js} +51 -10
- package/chunks/{chunk-FWH4736Q.js → chunk-O6BFERWN.js} +3 -3
- package/chunks/{chunk-UKADFFL2.js → chunk-OFVAS4AR.js} +1 -1
- package/chunks/{chunk-C55CR5I4.js → chunk-OVTPETDL.js} +6 -6
- package/chunks/chunk-PLEBBGHL.js +1401 -0
- package/chunks/{chunk-Z6KFLEG7.js → chunk-PSPAM24S.js} +1 -0
- package/chunks/{chunk-RRCNEW2A.js → chunk-PWR6BQ3U.js} +58 -4
- package/chunks/{chunk-SHK2SIR5.js → chunk-QA2B26PL.js} +4 -4
- package/chunks/{chunk-NFIDVZND.js → chunk-QB3KS3N3.js} +2 -21
- package/chunks/{chunk-NUQFUXOG.js → chunk-QTNCGZHQ.js} +2 -0
- package/chunks/{chunk-QJVZLILI.js → chunk-R7OO56VZ.js} +1 -1
- package/chunks/{chunk-MFCWL4LI.js → chunk-SK6VACCM.js} +936 -481
- package/chunks/{chunk-SD7Y2PMC.js → chunk-SM66GFKJ.js} +2 -2
- package/chunks/{chunk-ADJD4LZF.js → chunk-SNMUO5Z7.js} +1 -1
- package/chunks/{chunk-NXWYCSPL.js → chunk-SOA4HKRJ.js} +1 -1
- package/chunks/{chunk-IRKQ4YYX.js → chunk-SVWWF5TZ.js} +29 -1
- package/chunks/{chunk-YLFICBYK.js → chunk-SYKPMH2X.js} +3 -3
- package/chunks/{chunk-5HBA2Z7V.js → chunk-TGNNLRC3.js} +2 -3
- package/chunks/{chunk-AX23QSX3.js → chunk-TRQNRP2H.js} +4 -4
- package/chunks/{chunk-AUJOWIT5.js → chunk-UQOP2APG.js} +4 -24
- package/chunks/{chunk-HY3DXYZK.js → chunk-UYDQYDW2.js} +1 -1
- package/chunks/{chunk-IGOIYZBG.js → chunk-VAWM3A5N.js} +2 -2
- package/chunks/{chunk-6KYWU726.js → chunk-VJJXG73H.js} +417 -292
- package/chunks/{chunk-ZNI3V2XA.js → chunk-VJWJOKOQ.js} +2 -2
- package/chunks/{chunk-AWDF462I.js → chunk-VR6Y23FW.js} +2 -2
- package/chunks/{chunk-T7TP5UQL.js → chunk-VX2NR3SD.js} +21 -6
- package/chunks/{chunk-65GHQ4FX.js → chunk-WDVV3LRM.js} +707 -216
- package/chunks/{chunk-KP5QK3FB.js → chunk-WEU6O6VN.js} +397 -54
- package/chunks/{chunk-OHOO527W.js → chunk-WG7BL3FY.js} +52 -2
- package/chunks/{chunk-VU7O7CGQ.js → chunk-XDNFODER.js} +1 -1
- package/chunks/{chunk-YHDGABDC.js → chunk-XKBFYTCD.js} +1 -1
- package/chunks/{chunk-RUMSY4ES.js → chunk-Y7YHAY32.js} +28 -10
- package/chunks/{chunk-7IKXTGZT.js → chunk-YI2YCNSP.js} +1 -1
- package/chunks/{chunk-B5FF3LRF.js → chunk-YIE6REQ5.js} +29 -17
- package/chunks/{chunk-E4VX6LXB.js → chunk-YZTGGCEE.js} +10 -2
- package/chunks/{chunk-TXAEXF2B.js → chunk-ZEFWBG2C.js} +737 -1136
- package/chunks/{chunk-AIMZIXZM.js → chunk-ZM2TCZZ7.js} +5 -7
- package/chunks/{chunk-ZT3XUGSU.js → chunk-ZZ7RVOTU.js} +135 -26
- package/chunks/{config-utils-F4CFJ4MW.js → config-utils-SXFK3G4X.js} +33 -32
- package/chunks/{contextCommand-OIIGGOMU.js → contextCommand-QFPD26QO.js} +31 -30
- package/chunks/{core-runtime-JEHLOGMB.js → core-runtime-VXKNBODM.js} +35 -33
- package/chunks/{create-sub-session-MVFBE5RA.js → create-sub-session-7WSQETFR.js} +30 -29
- package/chunks/{daemon-LCUELM6E.js → daemon-U2456K5H.js} +2 -2
- package/chunks/{daemon-git-worktree-guard-5FTKLJOU.js → daemon-git-worktree-guard-I4DCSDUS.js} +29 -28
- package/chunks/{daemon-status-provider-P6A5MPMW.js → daemon-status-provider-5UV56RI4.js} +36 -35
- package/chunks/{daemon-trust-policy-ZJ3NFYUO.js → daemon-trust-policy-DKIBWTKU.js} +36 -35
- package/chunks/{daemon-trust-policy-monitor-6SDLEW7S.js → daemon-trust-policy-monitor-CPSD7UKT.js} +36 -35
- package/chunks/{deferred-core-runtime-DWOXIU5S.js → deferred-core-runtime-D2RF35BL.js} +29 -28
- package/chunks/{discovery-TUM3ZQ6U.js → discovery-XP4RMDUM.js} +4 -2
- package/chunks/{dist-P6YWBITG.js → dist-6YDUH3BB.js} +817 -152
- package/chunks/{dist-T4PRA5EZ.js → dist-BNQVF565.js} +2 -8
- package/chunks/{dist-AI25RVRA.js → dist-F34J4FZX.js} +1 -1
- package/chunks/{dist-3H3WODVS.js → dist-F6JLAJLE.js} +1 -1
- package/chunks/{dist-NXW4DUUX.js → dist-K5GHMXIG.js} +2 -2
- package/chunks/{dist-YNQU4CKC.js → dist-NP7QKLVG.js} +2 -2
- package/chunks/{dist-VCAS67N5.js → dist-UFTFGI6I.js} +1 -1
- package/chunks/{dist-I74QLLQS.js → dist-XLV33CLY.js} +1 -2
- package/chunks/{dist-XINEKB5A.js → dist-ZDNJK74R.js} +3 -7
- package/chunks/{edit-WPVXLL3T.js → edit-4IBADZ3O.js} +20 -20
- package/chunks/{enter-worktree-5A6VW6BN.js → enter-worktree-YFTKHXHZ.js} +2 -2
- package/chunks/{enterPlanMode-JSODW7E2.js → enterPlanMode-YN3GPQU5.js} +20 -20
- package/chunks/{environment-5LLJ3I3W.js → environment-E272IJMF.js} +32 -31
- package/chunks/{errors-IQT3YZEP.js → errors-CVAH3RWQ.js} +31 -30
- package/chunks/{exit-worktree-QV7E7KP6.js → exit-worktree-NF2XEMES.js} +3 -3
- package/chunks/{exitPlanMode-DDVFYNW4.js → exitPlanMode-24J5IHGC.js} +20 -20
- package/chunks/{fast-path-PAUQQEVU.js → fast-path-M5IDBMXF.js} +4 -4
- package/chunks/{fast-path-settings-ISEJPRYE.js → fast-path-settings-SATXY3PD.js} +3 -3
- package/chunks/{glob-SQ7CTZ7F.js → glob-ERBD7JYP.js} +20 -20
- package/chunks/{goal-tools-UWZRCLQB.js → goal-tools-245ULLQT.js} +20 -20
- package/chunks/{handleAutoUpdate-RUPZZTSG.js → handleAutoUpdate-JDZHHZKK.js} +32 -31
- package/chunks/{i18n-SF5MPWEB.js → i18n-LA4D5IXM.js} +32 -29
- package/chunks/{image-gen-Q3RUTVKR.js → image-gen-XP4NNIYG.js} +4 -4
- package/chunks/{initializer-CK4WPYZG.js → initializer-SHPTSWUZ.js} +36 -35
- package/chunks/{installationInfo-IRPQEYRF.js → installationInfo-QEQEPB3G.js} +29 -28
- package/chunks/{list-E3PS3EBJ.js → list-IBHCQWTF.js} +39 -38
- package/chunks/{list-agents-I5TRH3J7.js → list-agents-EDPZCGKN.js} +5 -4
- package/chunks/{llm-JQKBOYAF.js → llm-JAWCQLA4.js} +81 -75
- package/chunks/{llm-content-generator-2QWGBW42.js → llm-content-generator-GOV3A23T.js} +23 -8
- package/chunks/{loadedSettingsAdapter-DGXGVYZS.js → loadedSettingsAdapter-RVE2GNVU.js} +36 -35
- package/chunks/{loggingContentGenerator-ZYURLJKK.js → loggingContentGenerator-SSHNN5YW.js} +22 -22
- package/chunks/{managed-npm-update-HTHR63EA.js → managed-npm-update-BHSTITQO.js} +29 -28
- package/chunks/{mcp-I7G2AEWS.js → mcp-6ZZ7P2HU.js} +36 -35
- package/chunks/{monitor-4R76BCRZ.js → monitor-RKK6GSHG.js} +20 -20
- package/chunks/{nonInteractiveCli-24OQ3VP2.js → nonInteractiveCli-UQHP3G6P.js} +76 -72
- package/chunks/{notebook-edit-PPSH7FEX.js → notebook-edit-YM47A7WO.js} +20 -20
- package/chunks/{open-with-auth-D6JD6LDS.js → open-with-auth-6MVIHMXB.js} +1 -1
- package/chunks/{openaiContentGenerator-K7V5EO7F.js → openaiContentGenerator-FHKDWNI2.js} +11 -11
- package/chunks/{pidfile-TGIUY2GG.js → pidfile-SIIEJEEH.js} +32 -29
- package/chunks/{processUtils-3USXUQWX.js → processUtils-JF7CWBJC.js} +2 -2
- package/chunks/{prompt-terminal-ledger-XHVZRXJI.js → prompt-terminal-ledger-FXXHAEQU.js} +30 -29
- package/chunks/{qwenContentGenerator-MPBOQB64.js → qwenContentGenerator-KFJ77JP6.js} +24 -24
- package/chunks/{qwenOAuth2-BS5D2LYV.js → qwenOAuth2-KX6LVYQ3.js} +4 -4
- package/chunks/{read-file-R256LDWQ.js → read-file-S2NOCBIL.js} +4 -4
- package/chunks/{resumeHistoryUtils-S43LTFHD.js → resumeHistoryUtils-QHHPSQWU.js} +33 -32
- package/chunks/{ripGrep-L7HPZ75Y.js → ripGrep-F6TNOJUO.js} +5 -5
- package/chunks/{run-qwen-serve-CTFL5R6U.js → run-qwen-serve-KYBDQRDD.js} +229 -79
- package/chunks/{runtime-FS5TL6P7.js → runtime-3WNOFLCR.js} +43 -40
- package/chunks/{scheduled-tasks-QXPV3Q35.js → scheduled-tasks-RNBH56DJ.js} +34 -33
- package/chunks/{scheduler-EXU5HMVK.js → scheduler-ERMW7Q7B.js} +31 -30
- package/chunks/{send-message-GQKXGMPI.js → send-message-V5T3NMFM.js} +4 -4
- package/chunks/{serve-ITJC7WNN.js → serve-7NV46RMP.js} +36 -35
- package/chunks/{server-6JQY3PTU.js → server-6RZJR5QF.js} +1358 -932
- package/chunks/{session-PJDEKXD4.js → session-Z4EV7NVV.js} +107 -78
- package/chunks/{session-attachments-root-L37ORSST.js → session-attachments-root-SG5FC52X.js} +29 -28
- package/chunks/{session-pr-refresh-WIFD52YL.js → session-pr-refresh-ILC4Z3ZM.js} +33 -32
- package/chunks/{settings-LO6J5SAZ.js → settings-Y47SPE3X.js} +35 -34
- package/chunks/{shell-ANAFVYGR.js → shell-YBVCOPVO.js} +20 -20
- package/chunks/{skill-SHJWKSPH.js → skill-AXC63EBA.js} +4 -4
- package/chunks/{skill-settings-GX3XHZ5Q.js → skill-settings-AFPAYGLO.js} +35 -34
- package/chunks/{spawnChannel-WE42VBKM.js → spawnChannel-ZFL4J2V3.js} +29 -28
- package/chunks/{standalone-update-CWDIKJRP.js → standalone-update-Y2OZPLNJ.js} +31 -30
- package/chunks/{start-opentui-ui-BBHGFOTF.js → start-opentui-ui-G6TKT4LI.js} +2270 -1026
- package/chunks/{startInteractiveUI-FQX7LUYP.js → startInteractiveUI-YTNDPW7J.js} +1789 -2211
- package/chunks/{task-create-PMAFST2T.js → task-create-MWXJFRRM.js} +3 -3
- package/chunks/{task-list-R2HSY2NC.js → task-list-EYO3FE57.js} +2 -2
- package/chunks/{task-update-JYC57USF.js → task-update-2JJJRHMT.js} +3 -3
- package/chunks/{team-create-WKTPCH6D.js → team-create-BUFLGGSH.js} +20 -20
- package/chunks/{team-delete-CBHVBTPB.js → team-delete-IQZ6XGFI.js} +2 -2
- package/chunks/{team-plan-approval-Y23DL7WR.js → team-plan-approval-OUWWM42U.js} +20 -20
- package/chunks/{terminal-image-renderer-B646HBDW.js → terminal-image-renderer-WH2WV5ES.js} +29 -28
- package/chunks/{theme-manager-BNWESY26.js → theme-manager-5UDRARM2.js} +29 -28
- package/chunks/{tool-search-PVQ5O5Y2.js → tool-search-MCDIRPHN.js} +4 -4
- package/chunks/{total-session-admission-P5Z43KNW.js → total-session-admission-VL27U74Z.js} +33 -32
- package/chunks/{trustedFolders-FH2LT2MZ.js → trustedFolders-MSXT4VDD.js} +30 -29
- package/chunks/{update-relaunch-WOWTKJSN.js → update-relaunch-JKLEWVCB.js} +5 -5
- package/chunks/{updateCheck-3MYFMM35.js → updateCheck-ARTHAJT2.js} +31 -30
- package/chunks/{useAutoAcceptIndicator-Q7ZRRRKO.js → useAutoAcceptIndicator-YEAAGYVU.js} +38 -37
- package/chunks/{validateNonInterActiveAuth-MYEWJX3G.js → validateNonInterActiveAuth-EMRQKH5S.js} +71 -69
- package/chunks/{version-RO2FPO76.js → version-HFQU35WD.js} +3 -1
- package/chunks/{web-fetch-QAKY2LUA.js → web-fetch-QBXAO6VF.js} +7 -7
- package/chunks/{web-search-XA5Z4ZCD.js → web-search-2URQXA3A.js} +201 -13
- package/chunks/{web-shell-static-POZHGGXE.js → web-shell-static-BFDESDD4.js} +5 -4
- package/chunks/{workflow-QFIOCMDM.js → workflow-JDD6WDAH.js} +211 -75
- package/chunks/{workspace-providers-status-B2UD7RAG.js → workspace-providers-status-B4IKR6YJ.js} +38 -37
- package/chunks/{workspace-registration-store-VZLRTI3Q.js → workspace-registration-store-PJ3YHR45.js} +1 -2
- package/chunks/{workspace-registry-GYOGG6TM.js → workspace-registry-WVYJ5UGB.js} +33 -32
- package/chunks/{workspace-runtime-coordinator-7KRXGQ4V.js → workspace-runtime-coordinator-DXL5YVAG.js} +33 -32
- package/chunks/{workspace-service-DJEYGJE4.js → workspace-service-QNGAMVH7.js} +40 -39
- package/chunks/{workspace-skills-status-MOKNESUC.js → workspace-skills-status-BEISJIII.js} +36 -35
- package/chunks/{workspace-trust-reconciler-AXOSUTQW.js → workspace-trust-reconciler-ORYJF5L4.js} +40 -39
- package/chunks/{write-file-QOYVHAKK.js → write-file-DWLKFBTJ.js} +21 -21
- package/chunks/{zoom-image-UCCLGFNC.js → zoom-image-BYVIXSNQ.js} +4 -4
- package/cli.js +13 -13
- package/export-transcript-document.js +123 -119
- package/package.json +4 -4
- package/web-shell/assets/{abnfDiagram-VCTEODGH-CTstZpXw.js → abnfDiagram-VCTEODGH-C_8kzsly.js} +1 -1
- package/web-shell/assets/{arc-DKW0mbPo.js → arc-CDg7Zfpm.js} +1 -1
- package/web-shell/assets/{architectureDiagram-5GKGNRK7-DkMpJ42t.js → architectureDiagram-5GKGNRK7-DZzdCWyF.js} +1 -1
- package/web-shell/assets/{blockDiagram-NRAW4CY4-7Cp1_4i3.js → blockDiagram-NRAW4CY4-DI3B4gyR.js} +1 -1
- package/web-shell/assets/{c4Diagram-UCG6FXSJ-BfaoSlBK.js → c4Diagram-UCG6FXSJ-CfOgwHZW.js} +1 -1
- package/web-shell/assets/channel-e4xwS72w.js +1 -0
- package/web-shell/assets/{chunk-2Q5K7J3B-_n1qzAio.js → chunk-2Q5K7J3B-B_PUth0g.js} +1 -1
- package/web-shell/assets/{chunk-5VM5RSS4-0cira5ZV.js → chunk-5VM5RSS4-CrKtvBIL.js} +1 -1
- package/web-shell/assets/{chunk-F27PBJKO-DseRXSHC.js → chunk-F27PBJKO-B4z2n8Py.js} +1 -1
- package/web-shell/assets/{chunk-G27WJ6UU-BehQWin0.js → chunk-G27WJ6UU-BUtrFEO8.js} +1 -1
- package/web-shell/assets/{chunk-JWPE2WC7-B5ftg1Bb.js → chunk-JWPE2WC7-Cqw3aXW0.js} +1 -1
- package/web-shell/assets/{chunk-LCL6LL3I-D7rnbVdk.js → chunk-LCL6LL3I-CZolnvls.js} +1 -1
- package/web-shell/assets/{chunk-POPQ4Y6H-2Bp-Orju.js → chunk-POPQ4Y6H-DivgasCa.js} +1 -1
- package/web-shell/assets/{chunk-SVP7TREG-CD2goGva.js → chunk-SVP7TREG--seyb1B6.js} +1 -1
- package/web-shell/assets/{chunk-XXDRQBXY-DzQt-Rji.js → chunk-XXDRQBXY-D7pHtuVM.js} +1 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-CzXfUUOt.js +1 -0
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-CzXfUUOt.js +1 -0
- package/web-shell/assets/{cose-bilkent-JH36ORCC-C-BZXSUn.js → cose-bilkent-JH36ORCC-4MWaRF_3.js} +1 -1
- package/web-shell/assets/csv-CX7rUNeC.svg +1 -0
- package/web-shell/assets/{cynefin-OW5HDTMX-BTcvowe1.js → cynefin-OW5HDTMX-nhJhAjgD.js} +1 -1
- package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-BoUE6K81.js → cynefinDiagram-5FMLGOSQ-NF-PwXlq.js} +1 -1
- package/web-shell/assets/{dagre-3AP2YEHR-BHxy9xeB.js → dagre-3AP2YEHR-Bu0ncdWP.js} +1 -1
- package/web-shell/assets/{diagram-S7CK7UJ4-DMiJIvDT.js → diagram-S7CK7UJ4-CsvhFHZC.js} +1 -1
- package/web-shell/assets/{diagram-UQ7AKVKN-DXV09Aes.js → diagram-UQ7AKVKN-Ck61sIB3.js} +1 -1
- package/web-shell/assets/{diagram-VSXAHHWV-CocpRomV.js → diagram-VSXAHHWV-D0171zrb.js} +1 -1
- package/web-shell/assets/{diagram-VX7I27RA-DL7nqtb4.js → diagram-VX7I27RA-DvdxY4UL.js} +1 -1
- package/web-shell/assets/{diagram-Z3DM3KII-CPZ2Jux_.js → diagram-Z3DM3KII-CGGpseiB.js} +1 -1
- package/web-shell/assets/{ebnfDiagram-PWID7BFC-BX-eVNsX.js → ebnfDiagram-PWID7BFC-K8-QMvY8.js} +1 -1
- package/web-shell/assets/{erDiagram-SSCWMZ5O-CPy_Ir6y.js → erDiagram-SSCWMZ5O-D316nAem.js} +1 -1
- package/web-shell/assets/{flowDiagram-A5DVABFB-eknAOte9.js → flowDiagram-A5DVABFB-B7siy_mn.js} +1 -1
- package/web-shell/assets/{ganttDiagram-EL5Y4UJY-crAxw_t7.js → ganttDiagram-EL5Y4UJY-BZQDxzTu.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-M29pa3Tc.js → gitGraphDiagram-WWUBYQGX-DZynLCSV.js} +1 -1
- package/web-shell/assets/{index-C9R-iojE.js → index-9ie6xLTM.js} +1 -1
- package/web-shell/assets/index-DirkXQEg.js +2164 -0
- package/web-shell/assets/index-DzdST_7L.css +36 -0
- package/web-shell/assets/{infoDiagram-RXCK75RN-XqspXdOU.js → infoDiagram-RXCK75RN-B0gr769A.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-5VMMS53U-C5KFS-7j.js → ishikawaDiagram-5VMMS53U-0pQFfjvX.js} +1 -1
- package/web-shell/assets/{journeyDiagram-EYS64GPL-Cc57LVRo.js → journeyDiagram-EYS64GPL-DEGtClWb.js} +1 -1
- package/web-shell/assets/{kanban-definition-3QL26DDD-C81OG-AI.js → kanban-definition-3QL26DDD-CnN8gPzw.js} +1 -1
- package/web-shell/assets/{layout-CFVu37BB.js → layout-C_70RhaT.js} +1 -1
- package/web-shell/assets/{linear-ChBxdtWf.js → linear-BJ2ZLmcq.js} +1 -1
- package/web-shell/assets/{mermaid.core-CMLfue0w.js → mermaid.core-RlY0zPNC.js} +6 -6
- package/web-shell/assets/{mindmap-definition-FBJOCRG2-DFsvJThp.js → mindmap-definition-FBJOCRG2-CpVAxTNl.js} +1 -1
- package/web-shell/assets/{pegDiagram-XKGWAZYB-BzpRzM4F.js → pegDiagram-XKGWAZYB-DmrSv3hD.js} +1 -1
- package/web-shell/assets/{pieDiagram-E7YTZNPT-Cv0Kankl.js → pieDiagram-E7YTZNPT-CJmgp8KJ.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-AXDQQJYC-Bh2BJ3Ay.js → quadrantDiagram-AXDQQJYC-UsgOyNco.js} +1 -1
- package/web-shell/assets/{railroadDiagram-O6MQD6OU-y8rNDdDS.js → railroadDiagram-O6MQD6OU-DQ6gMs_W.js} +1 -1
- package/web-shell/assets/{requirementDiagram-EFPCY7ZU-C0m2DKJ_.js → requirementDiagram-EFPCY7ZU-DhqadamF.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-P5KCCOFB-BzdGnSF4.js → sankeyDiagram-P5KCCOFB-R4WnURaE.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-DPzAVmzz.js → sequenceDiagram-WJ2MYXX4-D7BwMi_D.js} +1 -1
- package/web-shell/assets/{sizeCapture-X5ZJPWSS-LcHG28Zh.js → sizeCapture-X5ZJPWSS-Bqngz088.js} +1 -1
- package/web-shell/assets/{stateDiagram-HBIQ2CUA-C1Bzy3IT.js → stateDiagram-HBIQ2CUA-DwaXPGqn.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-8GCQZAvv.js +1 -0
- package/web-shell/assets/{swimlanes-XN3QIQJK-Bftk8V64.js → swimlanes-XN3QIQJK-BsaLeRDY.js} +1 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-BoRBF2Yw.js +8 -0
- package/web-shell/assets/{timeline-definition-24CTP7MA-BfXHcN1A.js → timeline-definition-24CTP7MA-NJ9G-NUU.js} +1 -1
- package/web-shell/assets/{vennDiagram-4TSXK5OY-DRSlI9-V.js → vennDiagram-4TSXK5OY-Ca3W4rSq.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-VM6X3IG4-CaLmqGau.js → wardleyDiagram-VM6X3IG4-OabvjC-6.js} +1 -1
- package/web-shell/assets/{xychartDiagram-S5SC5T6Z-8lgUT6e8.js → xychartDiagram-S5SC5T6Z-C7rbjvpc.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-2LD5U7Q3.js +0 -114
- package/chunks/chunk-3UMWOKJC.js +0 -78
- package/chunks/chunk-IQAFKVXS.js +0 -22
- package/chunks/chunk-X35VIWWJ.js +0 -276
- package/chunks/chunk-ZJ2LM2SI.js +0 -198
- package/web-shell/assets/channel-CQx7VSAp.js +0 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-C-Uz8hHk.js +0 -1
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-C-Uz8hHk.js +0 -1
- package/web-shell/assets/index-B4TLaxWs.js +0 -2142
- package/web-shell/assets/index-CCrkEbzz.css +0 -36
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-LuuL5byY.js +0 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-COmnNq8s.js +0 -8
|
@@ -698,6 +698,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
698
698
|
channelLoopToolHandlers = [];
|
|
699
699
|
knownSessionIds = /* @__PURE__ */ new Set();
|
|
700
700
|
sessionBindingTokens = /* @__PURE__ */ new Map();
|
|
701
|
+
toolCallKindsBySession = /* @__PURE__ */ new Map();
|
|
701
702
|
channelLoopMcpRegistered = false;
|
|
702
703
|
channelLoopMcpRegistration = null;
|
|
703
704
|
pendingPermissions = /* @__PURE__ */ new Map();
|
|
@@ -743,6 +744,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
743
744
|
this.resolvePendingPermissions();
|
|
744
745
|
this.knownSessionIds.clear();
|
|
745
746
|
this.sessionBindingTokens.clear();
|
|
747
|
+
this.toolCallKindsBySession.clear();
|
|
746
748
|
this.connection = null;
|
|
747
749
|
this.child = null;
|
|
748
750
|
this.emit("disconnected", code, signal);
|
|
@@ -906,6 +908,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
906
908
|
if (!this.knownSessionIds.delete(sessionId))
|
|
907
909
|
return;
|
|
908
910
|
this.sessionBindingTokens.delete(sessionId);
|
|
911
|
+
this.toolCallKindsBySession.delete(sessionId);
|
|
909
912
|
this.resolvePendingPermissions(sessionId);
|
|
910
913
|
const conn = this.connection;
|
|
911
914
|
if (!conn || !this.isConnected)
|
|
@@ -930,6 +933,7 @@ var AcpBridge = class extends EventEmitter {
|
|
|
930
933
|
this.resolvePendingPermissions();
|
|
931
934
|
this.knownSessionIds.clear();
|
|
932
935
|
this.sessionBindingTokens.clear();
|
|
936
|
+
this.toolCallKindsBySession.clear();
|
|
933
937
|
if (this.child) {
|
|
934
938
|
this.child.kill();
|
|
935
939
|
this.child = null;
|
|
@@ -968,19 +972,44 @@ var AcpBridge = class extends EventEmitter {
|
|
|
968
972
|
}
|
|
969
973
|
break;
|
|
970
974
|
}
|
|
971
|
-
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
|
+
}
|
|
972
995
|
const event = {
|
|
973
996
|
sessionId,
|
|
974
|
-
toolCallId
|
|
975
|
-
kind
|
|
997
|
+
toolCallId,
|
|
998
|
+
kind,
|
|
976
999
|
title: update["title"] || "",
|
|
977
1000
|
status: update["status"] || "pending",
|
|
978
1001
|
rawInput: update["rawInput"]
|
|
979
1002
|
};
|
|
980
|
-
if (event.status === "pending" || event.status === "in_progress") {
|
|
1003
|
+
if (type === "tool_call" && (event.status === "pending" || event.status === "in_progress")) {
|
|
981
1004
|
this.emitResponseBoundary(sessionId);
|
|
982
1005
|
}
|
|
983
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
|
+
}
|
|
984
1013
|
break;
|
|
985
1014
|
}
|
|
986
1015
|
case "plan": {
|
|
@@ -1216,118 +1245,6 @@ init_esbuild_shims();
|
|
|
1216
1245
|
import { basename as basename3, join as join5 } from "node:path";
|
|
1217
1246
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
1218
1247
|
|
|
1219
|
-
// packages/channels/base/dist/BlockStreamer.js
|
|
1220
|
-
init_esbuild_shims();
|
|
1221
|
-
var BlockStreamer = class {
|
|
1222
|
-
static {
|
|
1223
|
-
__name(this, "BlockStreamer");
|
|
1224
|
-
}
|
|
1225
|
-
buffer = "";
|
|
1226
|
-
idleTimer = null;
|
|
1227
|
-
sending = Promise.resolve();
|
|
1228
|
-
opts;
|
|
1229
|
-
/** Number of blocks emitted so far. */
|
|
1230
|
-
blockCount = 0;
|
|
1231
|
-
constructor(opts) {
|
|
1232
|
-
this.opts = opts;
|
|
1233
|
-
}
|
|
1234
|
-
/** Feed a new text chunk from the agent stream. */
|
|
1235
|
-
push(chunk) {
|
|
1236
|
-
this.buffer += chunk;
|
|
1237
|
-
this.clearIdleTimer();
|
|
1238
|
-
this.checkEmit();
|
|
1239
|
-
if (this.buffer.length > 0 && this.opts.idleMs > 0) {
|
|
1240
|
-
this.idleTimer = setTimeout(() => this.onIdle(), this.opts.idleMs);
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
/** Flush all remaining buffered text. Awaits all pending sends. */
|
|
1244
|
-
async flush() {
|
|
1245
|
-
this.clearIdleTimer();
|
|
1246
|
-
if (this.buffer.length > 0) {
|
|
1247
|
-
this.emitBlock(this.buffer);
|
|
1248
|
-
this.buffer = "";
|
|
1249
|
-
}
|
|
1250
|
-
await this.sending;
|
|
1251
|
-
}
|
|
1252
|
-
/** Drop buffered text and cancel future idle emission. */
|
|
1253
|
-
stop() {
|
|
1254
|
-
this.clearIdleTimer();
|
|
1255
|
-
this.buffer = "";
|
|
1256
|
-
}
|
|
1257
|
-
/** Await already-queued sends without emitting the buffered text. */
|
|
1258
|
-
async drain() {
|
|
1259
|
-
await this.sending;
|
|
1260
|
-
}
|
|
1261
|
-
// ---------------------------------------------------------------------------
|
|
1262
|
-
// Internal
|
|
1263
|
-
// ---------------------------------------------------------------------------
|
|
1264
|
-
checkEmit() {
|
|
1265
|
-
while (this.buffer.length >= this.opts.maxChars) {
|
|
1266
|
-
const bp = this.findBreakPoint(this.buffer, this.opts.maxChars);
|
|
1267
|
-
this.emitBlock(this.buffer.slice(0, bp));
|
|
1268
|
-
this.buffer = this.buffer.slice(bp);
|
|
1269
|
-
}
|
|
1270
|
-
if (this.buffer.length >= this.opts.minChars) {
|
|
1271
|
-
const bp = this.findBlockBoundary(this.buffer);
|
|
1272
|
-
if (bp > 0) {
|
|
1273
|
-
this.emitBlock(this.buffer.slice(0, bp));
|
|
1274
|
-
this.buffer = this.buffer.slice(bp);
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
onIdle() {
|
|
1279
|
-
this.idleTimer = null;
|
|
1280
|
-
if (this.buffer.length >= this.opts.minChars) {
|
|
1281
|
-
this.emitBlock(this.buffer);
|
|
1282
|
-
this.buffer = "";
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
emitBlock(text) {
|
|
1286
|
-
const trimmed = text.trim();
|
|
1287
|
-
if (!trimmed)
|
|
1288
|
-
return;
|
|
1289
|
-
const block = /\n[^\S\n]*$/.test(text) ? `${trimmed}
|
|
1290
|
-
` : trimmed;
|
|
1291
|
-
this.blockCount++;
|
|
1292
|
-
this.sending = this.sending.then(() => this.opts.send(block)).catch(() => {
|
|
1293
|
-
});
|
|
1294
|
-
}
|
|
1295
|
-
/**
|
|
1296
|
-
* Find the last paragraph boundary (\n\n) in the buffer.
|
|
1297
|
-
* Returns the position after the boundary, or -1 if no suitable boundary
|
|
1298
|
-
* exists at or after minChars.
|
|
1299
|
-
*/
|
|
1300
|
-
findBlockBoundary(text) {
|
|
1301
|
-
const last = text.lastIndexOf("\n\n");
|
|
1302
|
-
if (last < 0 || last < this.opts.minChars)
|
|
1303
|
-
return -1;
|
|
1304
|
-
return last + 2;
|
|
1305
|
-
}
|
|
1306
|
-
/**
|
|
1307
|
-
* Find the best break point at or before maxPos.
|
|
1308
|
-
* Prefers paragraph break > newline > space > maxPos.
|
|
1309
|
-
*/
|
|
1310
|
-
findBreakPoint(text, maxPos) {
|
|
1311
|
-
const sub = text.slice(0, maxPos);
|
|
1312
|
-
const para = sub.lastIndexOf("\n\n");
|
|
1313
|
-
if (para > 0)
|
|
1314
|
-
return para + 2;
|
|
1315
|
-
const nl = sub.lastIndexOf("\n");
|
|
1316
|
-
if (nl > 0)
|
|
1317
|
-
return nl + 1;
|
|
1318
|
-
const sp = sub.lastIndexOf(" ");
|
|
1319
|
-
if (sp > 0)
|
|
1320
|
-
return sp + 1;
|
|
1321
|
-
return maxPos;
|
|
1322
|
-
}
|
|
1323
|
-
clearIdleTimer() {
|
|
1324
|
-
if (this.idleTimer !== null) {
|
|
1325
|
-
clearTimeout(this.idleTimer);
|
|
1326
|
-
this.idleTimer = null;
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
};
|
|
1330
|
-
|
|
1331
1248
|
// packages/channels/base/dist/ChannelProactiveDeliveryError.js
|
|
1332
1249
|
init_esbuild_shims();
|
|
1333
1250
|
var CHANNEL_PROACTIVE_DELIVERY_ERROR_CODE = "channel_proactive_delivery_error";
|
|
@@ -1763,6 +1680,49 @@ init_esbuild_shims();
|
|
|
1763
1680
|
import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, rmSync, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1764
1681
|
import { dirname as dirname3, isAbsolute, join as join4 } from "node:path";
|
|
1765
1682
|
import process2 from "node:process";
|
|
1683
|
+
function readDaemonHttpErrorCode(error) {
|
|
1684
|
+
let current = error;
|
|
1685
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
1686
|
+
if (typeof current !== "object" && typeof current !== "function" || current === null) {
|
|
1687
|
+
return void 0;
|
|
1688
|
+
}
|
|
1689
|
+
const record = current;
|
|
1690
|
+
if (record["name"] === "DaemonHttpError" && record["status"] === 409) {
|
|
1691
|
+
const body = record["body"];
|
|
1692
|
+
if (typeof body === "object" && body !== null && !Array.isArray(body)) {
|
|
1693
|
+
const code = body["code"];
|
|
1694
|
+
if (typeof code === "string" && code.length > 0)
|
|
1695
|
+
return code;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
current = record["cause"];
|
|
1699
|
+
}
|
|
1700
|
+
return void 0;
|
|
1701
|
+
}
|
|
1702
|
+
__name(readDaemonHttpErrorCode, "readDaemonHttpErrorCode");
|
|
1703
|
+
function readSupersededReplacementId(error) {
|
|
1704
|
+
let current = error;
|
|
1705
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
1706
|
+
if (typeof current !== "object" && typeof current !== "function" || current === null) {
|
|
1707
|
+
return void 0;
|
|
1708
|
+
}
|
|
1709
|
+
const record = current;
|
|
1710
|
+
if (record["name"] === "DaemonHttpError" && record["status"] === 409) {
|
|
1711
|
+
const body = record["body"];
|
|
1712
|
+
if (typeof body === "object" && body !== null && !Array.isArray(body)) {
|
|
1713
|
+
const typedBody = body;
|
|
1714
|
+
if (typedBody["code"] !== "worktree_session_superseded") {
|
|
1715
|
+
return void 0;
|
|
1716
|
+
}
|
|
1717
|
+
const replacement = typedBody["replacementSessionId"];
|
|
1718
|
+
return typeof replacement === "string" && replacement.length > 0 ? replacement : void 0;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
current = record["cause"];
|
|
1722
|
+
}
|
|
1723
|
+
return void 0;
|
|
1724
|
+
}
|
|
1725
|
+
__name(readSupersededReplacementId, "readSupersededReplacementId");
|
|
1766
1726
|
var SessionRouter = class {
|
|
1767
1727
|
static {
|
|
1768
1728
|
__name(this, "SessionRouter");
|
|
@@ -1773,9 +1733,11 @@ var SessionRouter = class {
|
|
|
1773
1733
|
// session ID → target
|
|
1774
1734
|
toCwd = /* @__PURE__ */ new Map();
|
|
1775
1735
|
// session ID → cwd
|
|
1736
|
+
toManagedMeta = /* @__PURE__ */ new Map();
|
|
1776
1737
|
creatingSessions = /* @__PURE__ */ new Map();
|
|
1777
1738
|
sessionLoadWindows = /* @__PURE__ */ new Set();
|
|
1778
1739
|
liveSessionIds = /* @__PURE__ */ new Set();
|
|
1740
|
+
staleBridgeBindings = /* @__PURE__ */ new Set();
|
|
1779
1741
|
routeTokens = /* @__PURE__ */ new Map();
|
|
1780
1742
|
lifecycleGeneration = 0;
|
|
1781
1743
|
bridge;
|
|
@@ -1797,6 +1759,7 @@ var SessionRouter = class {
|
|
|
1797
1759
|
setBridge(bridge) {
|
|
1798
1760
|
this.bridge = bridge;
|
|
1799
1761
|
this.liveSessionIds.clear();
|
|
1762
|
+
this.staleBridgeBindings.clear();
|
|
1800
1763
|
}
|
|
1801
1764
|
/** Set scope override for a specific channel. */
|
|
1802
1765
|
setChannelScope(channelName, scope) {
|
|
@@ -2072,12 +2035,12 @@ var SessionRouter = class {
|
|
|
2072
2035
|
this.endSessionLoad(loadWindow);
|
|
2073
2036
|
}
|
|
2074
2037
|
}
|
|
2075
|
-
async loadManagedSession(sessionId, target, workspaceCwd, expectedCwd = workspaceCwd, isolation = "shared") {
|
|
2038
|
+
async loadManagedSession(sessionId, target, workspaceCwd, expectedCwd = workspaceCwd, isolation = "shared", allowSupersededRedirect = true) {
|
|
2076
2039
|
if (this.liveSessionIds.has(sessionId)) {
|
|
2077
2040
|
const actualCwd = this.validateManagedSessionIdentity(this.bridge, sessionId, workspaceCwd, expectedCwd, isolation);
|
|
2078
2041
|
this.toTarget.set(sessionId, target);
|
|
2079
2042
|
this.toCwd.set(sessionId, actualCwd);
|
|
2080
|
-
return { loaded: false };
|
|
2043
|
+
return { loaded: false, sessionId };
|
|
2081
2044
|
}
|
|
2082
2045
|
const loadWindow = this.beginSessionLoad();
|
|
2083
2046
|
const lifecycleGeneration = this.lifecycleGeneration;
|
|
@@ -2085,6 +2048,9 @@ var SessionRouter = class {
|
|
|
2085
2048
|
const bindingToken = {};
|
|
2086
2049
|
let loadedSessionId;
|
|
2087
2050
|
try {
|
|
2051
|
+
if (this.staleBridgeBindings.delete(sessionId)) {
|
|
2052
|
+
await bridge.discardSession?.(sessionId).catch(() => void 0);
|
|
2053
|
+
}
|
|
2088
2054
|
loadedSessionId = await bridge.loadSession(sessionId, workspaceCwd, this.sessionOptions(target.channelName), bindingToken);
|
|
2089
2055
|
if (lifecycleGeneration !== this.lifecycleGeneration || bridge !== this.bridge) {
|
|
2090
2056
|
this.scheduleManagedDiscard(bridge, loadedSessionId, bindingToken);
|
|
@@ -2104,11 +2070,100 @@ var SessionRouter = class {
|
|
|
2104
2070
|
this.toTarget.set(sessionId, target);
|
|
2105
2071
|
this.toCwd.set(sessionId, actualCwd);
|
|
2106
2072
|
this.liveSessionIds.add(sessionId);
|
|
2107
|
-
return { loaded: true };
|
|
2073
|
+
return { loaded: true, sessionId };
|
|
2108
2074
|
} catch (error) {
|
|
2109
2075
|
if (loadedSessionId) {
|
|
2110
2076
|
await bridge.discardSession?.(loadedSessionId, bindingToken).catch(() => void 0);
|
|
2077
|
+
throw error;
|
|
2078
|
+
}
|
|
2079
|
+
const replacementId = readSupersededReplacementId(error);
|
|
2080
|
+
if (allowSupersededRedirect && replacementId !== void 0 && replacementId !== sessionId) {
|
|
2081
|
+
const redirected = await this.loadManagedSession(replacementId, target, workspaceCwd, expectedCwd, isolation, false);
|
|
2082
|
+
this.healSupersededRoute(sessionId, redirected.sessionId);
|
|
2083
|
+
return {
|
|
2084
|
+
loaded: redirected.loaded,
|
|
2085
|
+
sessionId: redirected.sessionId,
|
|
2086
|
+
redirectedFrom: sessionId
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
throw error;
|
|
2090
|
+
} finally {
|
|
2091
|
+
this.endSessionLoad(loadWindow);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
/**
|
|
2095
|
+
* Remap every route that still points at a superseded session to its
|
|
2096
|
+
* replacement, and drop the superseded id's bookkeeping. The manager's
|
|
2097
|
+
* own task registry heals separately (it owns the task-name mapping).
|
|
2098
|
+
*/
|
|
2099
|
+
healSupersededRoute(oldSessionId, newSessionId) {
|
|
2100
|
+
let changed = false;
|
|
2101
|
+
for (const [key, mappedSessionId] of this.toSession) {
|
|
2102
|
+
if (mappedSessionId !== oldSessionId)
|
|
2103
|
+
continue;
|
|
2104
|
+
this.invalidateRouteOperation(key);
|
|
2105
|
+
this.toSession.set(key, newSessionId);
|
|
2106
|
+
changed = true;
|
|
2107
|
+
}
|
|
2108
|
+
changed = this.toTarget.delete(oldSessionId) || changed;
|
|
2109
|
+
changed = this.toCwd.delete(oldSessionId) || changed;
|
|
2110
|
+
const managedMeta = this.toManagedMeta.get(oldSessionId);
|
|
2111
|
+
if (managedMeta !== void 0) {
|
|
2112
|
+
this.toManagedMeta.set(newSessionId, managedMeta);
|
|
2113
|
+
this.toManagedMeta.delete(oldSessionId);
|
|
2114
|
+
changed = true;
|
|
2115
|
+
}
|
|
2116
|
+
this.liveSessionIds.delete(oldSessionId);
|
|
2117
|
+
this.staleBridgeBindings.delete(oldSessionId);
|
|
2118
|
+
if (changed)
|
|
2119
|
+
this.persist();
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* Worktree reset: transfer the task session's checkout ownership to a
|
|
2123
|
+
* fresh replacement session on the daemon, validate the replacement's
|
|
2124
|
+
* attestation, and route it. The task registry itself is swapped by the
|
|
2125
|
+
* named-session manager (it owns the task-name mapping); this call only
|
|
2126
|
+
* wires the router's session bookkeeping.
|
|
2127
|
+
*
|
|
2128
|
+
* A failure past the daemon's marker flip rolls nothing back: the
|
|
2129
|
+
* registry keeps pointing at the old id, and the next selection's load
|
|
2130
|
+
* heals it through the superseded redirect — the failed reset drops the
|
|
2131
|
+
* old id from the live set so that load consults the daemon again.
|
|
2132
|
+
*/
|
|
2133
|
+
async replaceManagedWorktreeSession(sessionId, target, workspaceCwd, expectedCwd) {
|
|
2134
|
+
const bridge = this.bridge;
|
|
2135
|
+
if (!bridge.resetWorktreeSession) {
|
|
2136
|
+
throw new Error("Worktree reset is not supported by this bridge");
|
|
2137
|
+
}
|
|
2138
|
+
const loadWindow = this.beginSessionLoad();
|
|
2139
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
2140
|
+
const bindingToken = {};
|
|
2141
|
+
let replacementId;
|
|
2142
|
+
try {
|
|
2143
|
+
replacementId = await bridge.resetWorktreeSession(sessionId, workspaceCwd, this.sessionOptions(target.channelName), bindingToken);
|
|
2144
|
+
if (lifecycleGeneration !== this.lifecycleGeneration || bridge !== this.bridge) {
|
|
2145
|
+
this.scheduleManagedDiscard(bridge, replacementId, bindingToken);
|
|
2146
|
+
throw new Error("Managed session reset was invalidated");
|
|
2147
|
+
}
|
|
2148
|
+
if (typeof replacementId !== "string" || replacementId.length === 0) {
|
|
2149
|
+
throw new Error("Invalid session ID from bridge");
|
|
2150
|
+
}
|
|
2151
|
+
if (loadWindow.delete(replacementId)) {
|
|
2152
|
+
await bridge.discardSession?.(replacementId, bindingToken);
|
|
2153
|
+
throw new Error(`Managed session ${replacementId} died before reset completed`);
|
|
2111
2154
|
}
|
|
2155
|
+
const actualCwd = this.validateManagedSessionIdentity(bridge, replacementId, workspaceCwd, expectedCwd, "worktree");
|
|
2156
|
+
this.toTarget.set(replacementId, target);
|
|
2157
|
+
this.toCwd.set(replacementId, actualCwd);
|
|
2158
|
+
this.liveSessionIds.add(replacementId);
|
|
2159
|
+
this.forgetManagedSession(sessionId);
|
|
2160
|
+
return replacementId;
|
|
2161
|
+
} catch (error) {
|
|
2162
|
+
if (replacementId !== void 0) {
|
|
2163
|
+
await bridge.discardSession?.(replacementId, bindingToken).catch(() => void 0);
|
|
2164
|
+
}
|
|
2165
|
+
this.staleBridgeBindings.add(sessionId);
|
|
2166
|
+
this.liveSessionIds.delete(sessionId);
|
|
2112
2167
|
throw error;
|
|
2113
2168
|
} finally {
|
|
2114
2169
|
this.endSessionLoad(loadWindow);
|
|
@@ -2126,10 +2181,26 @@ var SessionRouter = class {
|
|
|
2126
2181
|
}
|
|
2127
2182
|
return canonicalWorktree;
|
|
2128
2183
|
}
|
|
2129
|
-
activateManagedSession(sessionId, target, cwd) {
|
|
2184
|
+
activateManagedSession(sessionId, target, cwd, managed) {
|
|
2185
|
+
if (managed?.isolation === "worktree" && !managed.workspaceCwd) {
|
|
2186
|
+
throw new Error("A worktree managed session requires its workspace cwd.");
|
|
2187
|
+
}
|
|
2188
|
+
const previousMeta = this.toManagedMeta.get(sessionId);
|
|
2189
|
+
if (managed?.isolation === "worktree") {
|
|
2190
|
+
this.toManagedMeta.set(sessionId, {
|
|
2191
|
+
isolation: "worktree",
|
|
2192
|
+
workspaceCwd: managed.workspaceCwd
|
|
2193
|
+
});
|
|
2194
|
+
} else {
|
|
2195
|
+
this.toManagedMeta.delete(sessionId);
|
|
2196
|
+
}
|
|
2197
|
+
const metaChanged = managed?.isolation === "worktree" ? previousMeta?.workspaceCwd !== managed.workspaceCwd : previousMeta !== void 0;
|
|
2130
2198
|
const key = this.routingKey(target.channelName, target.senderId, target.chatId, target.threadId);
|
|
2131
|
-
if (this.toSession.get(key) === sessionId)
|
|
2199
|
+
if (this.toSession.get(key) === sessionId) {
|
|
2200
|
+
if (metaChanged)
|
|
2201
|
+
this.persist();
|
|
2132
2202
|
return;
|
|
2203
|
+
}
|
|
2133
2204
|
this.invalidateRouteOperation(key);
|
|
2134
2205
|
this.toSession.set(key, sessionId);
|
|
2135
2206
|
this.toTarget.set(sessionId, target);
|
|
@@ -2147,17 +2218,18 @@ var SessionRouter = class {
|
|
|
2147
2218
|
}
|
|
2148
2219
|
changed = this.toTarget.delete(sessionId) || changed;
|
|
2149
2220
|
changed = this.toCwd.delete(sessionId) || changed;
|
|
2221
|
+
changed = this.toManagedMeta.delete(sessionId) || changed;
|
|
2150
2222
|
changed = this.liveSessionIds.delete(sessionId) || changed;
|
|
2223
|
+
this.staleBridgeBindings.delete(sessionId);
|
|
2151
2224
|
if (changed)
|
|
2152
2225
|
this.persist();
|
|
2153
2226
|
}
|
|
2154
2227
|
async detachManagedSession(sessionId) {
|
|
2155
2228
|
try {
|
|
2156
|
-
if (this.
|
|
2157
|
-
if (!this.bridge.discardSession) {
|
|
2158
|
-
throw new Error("Managed session detach is not supported");
|
|
2159
|
-
}
|
|
2229
|
+
if (this.bridge.discardSession) {
|
|
2160
2230
|
await this.bridge.discardSession(sessionId);
|
|
2231
|
+
} else if (this.liveSessionIds.has(sessionId)) {
|
|
2232
|
+
throw new Error("Managed session detach is not supported");
|
|
2161
2233
|
}
|
|
2162
2234
|
} finally {
|
|
2163
2235
|
this.forgetManagedSession(sessionId);
|
|
@@ -2213,6 +2285,9 @@ var SessionRouter = class {
|
|
|
2213
2285
|
if (this.toCwd.delete(sessionId)) {
|
|
2214
2286
|
removed = true;
|
|
2215
2287
|
}
|
|
2288
|
+
if (this.toManagedMeta.delete(sessionId)) {
|
|
2289
|
+
removed = true;
|
|
2290
|
+
}
|
|
2216
2291
|
this.liveSessionIds.delete(sessionId);
|
|
2217
2292
|
if (!removed && this.sessionLoadWindows.size > 0) {
|
|
2218
2293
|
for (const loadWindow of this.sessionLoadWindows) {
|
|
@@ -2242,6 +2317,7 @@ var SessionRouter = class {
|
|
|
2242
2317
|
this.toSession.delete(key);
|
|
2243
2318
|
this.toTarget.delete(sessionId);
|
|
2244
2319
|
this.toCwd.delete(sessionId);
|
|
2320
|
+
this.toManagedMeta.delete(sessionId);
|
|
2245
2321
|
this.liveSessionIds.delete(sessionId);
|
|
2246
2322
|
return sessionId;
|
|
2247
2323
|
}
|
|
@@ -2278,6 +2354,12 @@ var SessionRouter = class {
|
|
|
2278
2354
|
this.toSession.set(key, entry.sessionId);
|
|
2279
2355
|
this.toTarget.set(entry.sessionId, entry.target);
|
|
2280
2356
|
this.toCwd.set(entry.sessionId, entry.cwd);
|
|
2357
|
+
if (entry.isolation === "worktree" && entry.workspaceCwd !== void 0) {
|
|
2358
|
+
this.toManagedMeta.set(entry.sessionId, {
|
|
2359
|
+
isolation: "worktree",
|
|
2360
|
+
workspaceCwd: entry.workspaceCwd
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2281
2363
|
restored++;
|
|
2282
2364
|
}
|
|
2283
2365
|
if (persisted.dropped > 0)
|
|
@@ -2321,6 +2403,32 @@ var SessionRouter = class {
|
|
|
2321
2403
|
try {
|
|
2322
2404
|
this.assertOperationCurrent(operation);
|
|
2323
2405
|
const options = this.sessionOptions(entry.target.channelName);
|
|
2406
|
+
if (entry.isolation === "worktree" && entry.workspaceCwd !== void 0) {
|
|
2407
|
+
const managed = await this.loadManagedSession(entry.sessionId, entry.target, entry.workspaceCwd, entry.cwd, "worktree");
|
|
2408
|
+
try {
|
|
2409
|
+
this.assertOperationCurrent(operation);
|
|
2410
|
+
} catch (error) {
|
|
2411
|
+
if (![...this.toSession.values()].includes(managed.sessionId)) {
|
|
2412
|
+
void this.bridge.discardSession?.(managed.sessionId).catch(() => void 0);
|
|
2413
|
+
this.toTarget.delete(managed.sessionId);
|
|
2414
|
+
this.toCwd.delete(managed.sessionId);
|
|
2415
|
+
this.toManagedMeta.delete(managed.sessionId);
|
|
2416
|
+
this.liveSessionIds.delete(managed.sessionId);
|
|
2417
|
+
}
|
|
2418
|
+
throw error;
|
|
2419
|
+
}
|
|
2420
|
+
this.toSession.set(key, managed.sessionId);
|
|
2421
|
+
this.toManagedMeta.set(managed.sessionId, {
|
|
2422
|
+
isolation: "worktree",
|
|
2423
|
+
workspaceCwd: entry.workspaceCwd
|
|
2424
|
+
});
|
|
2425
|
+
reservation.resolve(managed.sessionId);
|
|
2426
|
+
if (managed.sessionId !== entry.sessionId) {
|
|
2427
|
+
changed = true;
|
|
2428
|
+
}
|
|
2429
|
+
restored++;
|
|
2430
|
+
continue;
|
|
2431
|
+
}
|
|
2324
2432
|
const sessionId = await this.bridge.loadSession(entry.sessionId, entry.cwd, options, operation);
|
|
2325
2433
|
try {
|
|
2326
2434
|
this.assertOperationCurrent(operation);
|
|
@@ -2373,9 +2481,11 @@ var SessionRouter = class {
|
|
|
2373
2481
|
this.toSession.clear();
|
|
2374
2482
|
this.toTarget.clear();
|
|
2375
2483
|
this.toCwd.clear();
|
|
2484
|
+
this.toManagedMeta.clear();
|
|
2376
2485
|
this.creatingSessions.clear();
|
|
2377
2486
|
this.sessionLoadWindows.clear();
|
|
2378
2487
|
this.liveSessionIds.clear();
|
|
2488
|
+
this.staleBridgeBindings.clear();
|
|
2379
2489
|
this.routeTokens.clear();
|
|
2380
2490
|
}
|
|
2381
2491
|
/** Clear in-memory state and delete persist file. Used on clean shutdown. */
|
|
@@ -2433,7 +2543,12 @@ var SessionRouter = class {
|
|
|
2433
2543
|
if (typeof target !== "object" || target === null)
|
|
2434
2544
|
return false;
|
|
2435
2545
|
const typedTarget = target;
|
|
2436
|
-
|
|
2546
|
+
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");
|
|
2547
|
+
if (!wellFormed)
|
|
2548
|
+
return false;
|
|
2549
|
+
if (entry["isolation"] === void 0)
|
|
2550
|
+
return true;
|
|
2551
|
+
return entry["isolation"] === "worktree" && typeof entry["workspaceCwd"] === "string" && entry["workspaceCwd"].length > 0;
|
|
2437
2552
|
}
|
|
2438
2553
|
persist() {
|
|
2439
2554
|
if (!this.persistPath)
|
|
@@ -2446,7 +2561,8 @@ var SessionRouter = class {
|
|
|
2446
2561
|
data[key] = {
|
|
2447
2562
|
sessionId,
|
|
2448
2563
|
target,
|
|
2449
|
-
cwd: this.toCwd.get(sessionId) ?? this.defaultCwd
|
|
2564
|
+
cwd: this.toCwd.get(sessionId) ?? this.defaultCwd,
|
|
2565
|
+
...this.toManagedMeta.get(sessionId) ?? {}
|
|
2450
2566
|
};
|
|
2451
2567
|
}
|
|
2452
2568
|
const dir = dirname3(this.persistPath);
|
|
@@ -2594,6 +2710,16 @@ import process3 from "node:process";
|
|
|
2594
2710
|
var REGISTRY_VERSION = 1;
|
|
2595
2711
|
var MAX_OPEN_TASKS = 8;
|
|
2596
2712
|
var TASK_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;
|
|
2713
|
+
var NamedSessionTaskError = class extends Error {
|
|
2714
|
+
static {
|
|
2715
|
+
__name(this, "NamedSessionTaskError");
|
|
2716
|
+
}
|
|
2717
|
+
taskName;
|
|
2718
|
+
constructor(message, taskName, options) {
|
|
2719
|
+
super(message, options);
|
|
2720
|
+
this.taskName = taskName;
|
|
2721
|
+
}
|
|
2722
|
+
};
|
|
2597
2723
|
var NamedSessionManager = class {
|
|
2598
2724
|
static {
|
|
2599
2725
|
__name(this, "NamedSessionManager");
|
|
@@ -2608,6 +2734,12 @@ var NamedSessionManager = class {
|
|
|
2608
2734
|
registry;
|
|
2609
2735
|
taskBySessionId;
|
|
2610
2736
|
ownerOperations = /* @__PURE__ */ new Map();
|
|
2737
|
+
/**
|
|
2738
|
+
* Superseded session id → the replacement its task moved onto. A queued turn
|
|
2739
|
+
* stays bound to the id it reserved, so the reservation lookup has to follow
|
|
2740
|
+
* the task or every turn after the first one is stranded on the old id.
|
|
2741
|
+
*/
|
|
2742
|
+
supersededSessionIds = /* @__PURE__ */ new Map();
|
|
2611
2743
|
constructor(options) {
|
|
2612
2744
|
this.channelName = options.channelName;
|
|
2613
2745
|
this.cwd = options.cwd;
|
|
@@ -2706,14 +2838,20 @@ var NamedSessionManager = class {
|
|
|
2706
2838
|
return task ? this.selection(owner, task) : void 0;
|
|
2707
2839
|
});
|
|
2708
2840
|
}
|
|
2841
|
+
/**
|
|
2842
|
+
* Reload a task a queued turn is already bound to. Resolves to the session
|
|
2843
|
+
* id the caller must dispatch on — the healed replacement when a superseded
|
|
2844
|
+
* redirect fired — or undefined when the task is no longer reservable.
|
|
2845
|
+
*/
|
|
2709
2846
|
resumeReserved(input, sessionId) {
|
|
2710
2847
|
return this.withOwnerLock(input, async () => {
|
|
2711
2848
|
const owner = await this.ensureOwner(input, false);
|
|
2712
|
-
const
|
|
2849
|
+
const reservedSessionId = this.supersededSessionIds.get(sessionId) ?? sessionId;
|
|
2850
|
+
const task = owner?.tasks.find((candidate) => candidate.sessionId === reservedSessionId && candidate.status === "open");
|
|
2713
2851
|
if (!task)
|
|
2714
|
-
return
|
|
2715
|
-
await this.loadTask(task, `Could not reload reserved task "${task.name}".`);
|
|
2716
|
-
return
|
|
2852
|
+
return void 0;
|
|
2853
|
+
const result = await this.loadTask(task, `Could not reload reserved task "${task.name}".`);
|
|
2854
|
+
return result.sessionId;
|
|
2717
2855
|
});
|
|
2718
2856
|
}
|
|
2719
2857
|
create(input, name, isolation = "shared") {
|
|
@@ -2757,7 +2895,10 @@ var NamedSessionManager = class {
|
|
|
2757
2895
|
await this.router.detachManagedSession(sessionId).catch(() => void 0);
|
|
2758
2896
|
throw error;
|
|
2759
2897
|
}
|
|
2760
|
-
this.router.activateManagedSession(sessionId, target, task.cwd
|
|
2898
|
+
this.router.activateManagedSession(sessionId, target, task.cwd, {
|
|
2899
|
+
isolation: task.isolation,
|
|
2900
|
+
workspaceCwd: this.cwd
|
|
2901
|
+
});
|
|
2761
2902
|
return this.selection(nextOwner, task);
|
|
2762
2903
|
});
|
|
2763
2904
|
}
|
|
@@ -2773,9 +2914,10 @@ var NamedSessionManager = class {
|
|
|
2773
2914
|
throw new Error("You already have eight open tasks. Close one before reopening another.");
|
|
2774
2915
|
}
|
|
2775
2916
|
const timestamp = this.nextTimestamp(owner);
|
|
2776
|
-
const
|
|
2917
|
+
const loadResult = await this.loadTask(task, `Could not load task "${task.name}". The current task was not changed.`);
|
|
2777
2918
|
const updatedTask = {
|
|
2778
2919
|
...task,
|
|
2920
|
+
sessionId: loadResult.sessionId,
|
|
2779
2921
|
status: "open",
|
|
2780
2922
|
updatedAt: timestamp,
|
|
2781
2923
|
lastSelectedAt: timestamp
|
|
@@ -2784,12 +2926,12 @@ var NamedSessionManager = class {
|
|
|
2784
2926
|
try {
|
|
2785
2927
|
this.commitOwner(nextOwner);
|
|
2786
2928
|
} catch (error) {
|
|
2787
|
-
if (loaded) {
|
|
2788
|
-
await this.router.detachManagedSession(
|
|
2929
|
+
if (loadResult.loaded) {
|
|
2930
|
+
await this.router.detachManagedSession(loadResult.sessionId).catch(() => void 0);
|
|
2789
2931
|
}
|
|
2790
2932
|
throw error;
|
|
2791
2933
|
}
|
|
2792
|
-
this.router.activateManagedSession(
|
|
2934
|
+
this.router.activateManagedSession(loadResult.sessionId, updatedTask.target, updatedTask.cwd, { isolation: updatedTask.isolation, workspaceCwd: this.cwd });
|
|
2793
2935
|
return this.selection(nextOwner, updatedTask);
|
|
2794
2936
|
});
|
|
2795
2937
|
}
|
|
@@ -2811,8 +2953,11 @@ var NamedSessionManager = class {
|
|
|
2811
2953
|
const timestamp = this.nextTimestamp(owner);
|
|
2812
2954
|
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;
|
|
2813
2955
|
let replacementLoaded = false;
|
|
2956
|
+
let replacementSessionId;
|
|
2814
2957
|
if (replacement) {
|
|
2815
|
-
|
|
2958
|
+
const replacementLoad = await this.loadTask(replacement, `Could not load fallback task "${replacement.name}". Task "${task.name}" was not closed.`);
|
|
2959
|
+
replacementLoaded = replacementLoad.loaded;
|
|
2960
|
+
replacementSessionId = replacementLoad.sessionId;
|
|
2816
2961
|
}
|
|
2817
2962
|
const closedTask = {
|
|
2818
2963
|
...task,
|
|
@@ -2822,6 +2967,7 @@ var NamedSessionManager = class {
|
|
|
2822
2967
|
let nextOwner = this.replaceTask(owner, closedTask, wasActive ? replacement?.name ?? null : owner.activeTaskName);
|
|
2823
2968
|
const selectedReplacement = replacement ? {
|
|
2824
2969
|
...replacement,
|
|
2970
|
+
sessionId: replacementSessionId ?? replacement.sessionId,
|
|
2825
2971
|
updatedAt: timestamp,
|
|
2826
2972
|
lastSelectedAt: timestamp
|
|
2827
2973
|
} : void 0;
|
|
@@ -2832,21 +2978,22 @@ var NamedSessionManager = class {
|
|
|
2832
2978
|
this.commitOwner(nextOwner);
|
|
2833
2979
|
} catch (error) {
|
|
2834
2980
|
if (replacement && replacementLoaded) {
|
|
2835
|
-
await this.router.detachManagedSession(replacement.sessionId).catch(() => void 0);
|
|
2981
|
+
await this.router.detachManagedSession(replacementSessionId ?? replacement.sessionId).catch(() => void 0);
|
|
2836
2982
|
}
|
|
2837
2983
|
throw error;
|
|
2838
2984
|
}
|
|
2839
2985
|
if (replacement) {
|
|
2840
|
-
this.router.activateManagedSession(replacement.sessionId, replacement.target, replacement.cwd);
|
|
2986
|
+
this.router.activateManagedSession(replacementSessionId ?? replacement.sessionId, replacement.target, replacement.cwd, { isolation: replacement.isolation, workspaceCwd: this.cwd });
|
|
2841
2987
|
}
|
|
2842
2988
|
try {
|
|
2843
2989
|
await this.router.detachManagedSession(task.sessionId);
|
|
2844
2990
|
} catch (error) {
|
|
2845
|
-
|
|
2991
|
+
const healedReplacement = replacement !== void 0 && replacementSessionId !== void 0 && replacementSessionId !== replacement.sessionId ? { ...replacement, sessionId: replacementSessionId } : void 0;
|
|
2992
|
+
this.commitOwner(healedReplacement ? this.replaceTask(owner, healedReplacement, owner.activeTaskName) : owner);
|
|
2846
2993
|
this.router.forgetManagedSession(task.sessionId);
|
|
2847
|
-
await this.loadTask(task, `Task "${task.name}" could not be restored after close failed.`);
|
|
2994
|
+
const restored = await this.loadTask(task, `Task "${task.name}" could not be restored after close failed.`);
|
|
2848
2995
|
if (wasActive) {
|
|
2849
|
-
this.router.activateManagedSession(
|
|
2996
|
+
this.router.activateManagedSession(restored.sessionId, task.target, task.cwd, { isolation: task.isolation, workspaceCwd: this.cwd });
|
|
2850
2997
|
}
|
|
2851
2998
|
throw new Error(`Failed to close task "${task.name}".`, {
|
|
2852
2999
|
cause: error
|
|
@@ -2867,10 +3014,36 @@ var NamedSessionManager = class {
|
|
|
2867
3014
|
const task = this.findTask(owner, owner.activeTaskName);
|
|
2868
3015
|
if (!task || task.status !== "open")
|
|
2869
3016
|
return void 0;
|
|
3017
|
+
const timestamp = this.nextTimestamp(owner);
|
|
2870
3018
|
if (task.isolation === "worktree") {
|
|
2871
|
-
|
|
3019
|
+
if (this.isBusy(task.sessionId)) {
|
|
3020
|
+
throw new Error(`Task "${task.name}" is busy. Wait for the running prompt to finish (or cancel it), then try again.`);
|
|
3021
|
+
}
|
|
3022
|
+
const sessionId2 = await this.resetWorktreeSession(task);
|
|
3023
|
+
const updatedTask2 = {
|
|
3024
|
+
...task,
|
|
3025
|
+
sessionId: sessionId2,
|
|
3026
|
+
updatedAt: timestamp,
|
|
3027
|
+
lastSelectedAt: timestamp
|
|
3028
|
+
};
|
|
3029
|
+
const nextOwner2 = this.replaceTask(owner, updatedTask2, task.name);
|
|
3030
|
+
try {
|
|
3031
|
+
this.commitOwner(nextOwner2);
|
|
3032
|
+
} catch (error) {
|
|
3033
|
+
await this.router.detachManagedSession(sessionId2).catch(() => void 0);
|
|
3034
|
+
throw error;
|
|
3035
|
+
}
|
|
3036
|
+
this.router.activateManagedSession(sessionId2, updatedTask2.target, updatedTask2.cwd, { isolation: updatedTask2.isolation, workspaceCwd: this.cwd });
|
|
3037
|
+
this.router.forgetManagedSession(task.sessionId);
|
|
3038
|
+
this.repointSupersededSessionIds(task.sessionId, sessionId2);
|
|
3039
|
+
this.supersededSessionIds.delete(task.sessionId);
|
|
3040
|
+
return {
|
|
3041
|
+
name: task.name,
|
|
3042
|
+
previousSessionId: task.sessionId,
|
|
3043
|
+
sessionId: sessionId2,
|
|
3044
|
+
worktreeKept: true
|
|
3045
|
+
};
|
|
2872
3046
|
}
|
|
2873
|
-
const timestamp = this.nextTimestamp(owner);
|
|
2874
3047
|
const sessionId = await this.createSession(task.target, task.isolation, `Could not reset task "${task.name}".`);
|
|
2875
3048
|
const updatedTask = {
|
|
2876
3049
|
...task,
|
|
@@ -2885,12 +3058,15 @@ var NamedSessionManager = class {
|
|
|
2885
3058
|
await this.router.detachManagedSession(sessionId).catch(() => void 0);
|
|
2886
3059
|
throw error;
|
|
2887
3060
|
}
|
|
2888
|
-
this.router.activateManagedSession(sessionId, updatedTask.target, updatedTask.cwd);
|
|
3061
|
+
this.router.activateManagedSession(sessionId, updatedTask.target, updatedTask.cwd, { isolation: updatedTask.isolation, workspaceCwd: this.cwd });
|
|
2889
3062
|
this.router.forgetManagedSession(task.sessionId);
|
|
3063
|
+
this.repointSupersededSessionIds(task.sessionId, sessionId);
|
|
3064
|
+
this.supersededSessionIds.delete(task.sessionId);
|
|
2890
3065
|
return {
|
|
2891
3066
|
name: task.name,
|
|
2892
3067
|
previousSessionId: task.sessionId,
|
|
2893
|
-
sessionId
|
|
3068
|
+
sessionId,
|
|
3069
|
+
worktreeKept: false
|
|
2894
3070
|
};
|
|
2895
3071
|
});
|
|
2896
3072
|
}
|
|
@@ -2960,12 +3136,17 @@ var NamedSessionManager = class {
|
|
|
2960
3136
|
throw new Error("The selected Channel task is unavailable.");
|
|
2961
3137
|
}
|
|
2962
3138
|
const release = reserve?.(task.sessionId);
|
|
3139
|
+
let activeRelease = release;
|
|
2963
3140
|
try {
|
|
2964
|
-
await this.loadTask(task, `Could not load task "${task.name}". No replacement session was created.`);
|
|
2965
|
-
|
|
2966
|
-
|
|
3141
|
+
const result = await this.loadTask(task, `Could not load task "${task.name}". No replacement session was created.`);
|
|
3142
|
+
if (result.sessionId !== task.sessionId && reserve) {
|
|
3143
|
+
release?.();
|
|
3144
|
+
activeRelease = reserve(result.sessionId);
|
|
3145
|
+
}
|
|
3146
|
+
this.router.activateManagedSession(result.sessionId, task.target, task.cwd, { isolation: task.isolation, workspaceCwd: this.cwd });
|
|
3147
|
+
return result.sessionId;
|
|
2967
3148
|
} catch (error) {
|
|
2968
|
-
|
|
3149
|
+
activeRelease?.();
|
|
2969
3150
|
throw error;
|
|
2970
3151
|
}
|
|
2971
3152
|
}
|
|
@@ -2998,9 +3179,55 @@ var NamedSessionManager = class {
|
|
|
2998
3179
|
}
|
|
2999
3180
|
async loadTask(task, failureMessage) {
|
|
3000
3181
|
try {
|
|
3001
|
-
|
|
3182
|
+
const result = await this.router.loadManagedSession(task.sessionId, task.target, this.cwd, task.cwd, task.isolation);
|
|
3183
|
+
if (result.redirectedFrom !== void 0 && result.sessionId !== task.sessionId) {
|
|
3184
|
+
try {
|
|
3185
|
+
this.healSupersededTask(task, result.sessionId);
|
|
3186
|
+
} catch {
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
return result;
|
|
3002
3190
|
} catch (error) {
|
|
3003
|
-
throw new
|
|
3191
|
+
throw new NamedSessionTaskError(failureMessage, task.name, {
|
|
3192
|
+
cause: error
|
|
3193
|
+
});
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
/**
|
|
3197
|
+
* Point a task at its replacement session after a superseded redirect
|
|
3198
|
+
* healed the route. No-op when the registry entry already moved on (a
|
|
3199
|
+
* concurrent reset under the same owner lock cannot interleave, but a
|
|
3200
|
+
* stale in-memory snapshot could).
|
|
3201
|
+
*/
|
|
3202
|
+
healSupersededTask(task, sessionId) {
|
|
3203
|
+
const owner = this.getOwner(task.target);
|
|
3204
|
+
if (!owner)
|
|
3205
|
+
return;
|
|
3206
|
+
const current = this.findTask(owner, task.name);
|
|
3207
|
+
if (!current || current.sessionId !== task.sessionId)
|
|
3208
|
+
return;
|
|
3209
|
+
const timestamp = this.nextTimestamp(owner);
|
|
3210
|
+
this.commitOwner(this.replaceTask(owner, { ...current, sessionId, updatedAt: timestamp }, owner.activeTaskName));
|
|
3211
|
+
this.repointSupersededSessionIds(task.sessionId, sessionId);
|
|
3212
|
+
this.supersededSessionIds.set(task.sessionId, sessionId);
|
|
3213
|
+
}
|
|
3214
|
+
/**
|
|
3215
|
+
* Follow every id that still resolves to `oldSessionId` onto its
|
|
3216
|
+
* replacement, so a task superseded more than once stays reachable from the
|
|
3217
|
+
* oldest id a turn is bound to and the map does not grow once per reset.
|
|
3218
|
+
*/
|
|
3219
|
+
repointSupersededSessionIds(oldSessionId, newSessionId) {
|
|
3220
|
+
for (const boundSessionId of [...this.supersededSessionIds.keys()]) {
|
|
3221
|
+
if (this.supersededSessionIds.get(boundSessionId) === oldSessionId) {
|
|
3222
|
+
this.supersededSessionIds.set(boundSessionId, newSessionId);
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
async resetWorktreeSession(task) {
|
|
3227
|
+
try {
|
|
3228
|
+
return await this.router.replaceManagedWorktreeSession(task.sessionId, task.target, this.cwd, task.cwd);
|
|
3229
|
+
} catch (error) {
|
|
3230
|
+
throw new NamedSessionTaskError(`Could not reset task "${task.name}".`, task.name, { cause: error });
|
|
3004
3231
|
}
|
|
3005
3232
|
}
|
|
3006
3233
|
async createSession(target, isolation, failureMessage) {
|
|
@@ -3991,6 +4218,45 @@ function isRecord2(value) {
|
|
|
3991
4218
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3992
4219
|
}
|
|
3993
4220
|
__name(isRecord2, "isRecord");
|
|
4221
|
+
var PERMISSION_COPY = {
|
|
4222
|
+
en: {
|
|
4223
|
+
toolUse: "Tool use",
|
|
4224
|
+
allowOnce: "Allow once",
|
|
4225
|
+
allowAlwaysProject: "always allow for this project",
|
|
4226
|
+
allowAlwaysUser: "always allow for this user",
|
|
4227
|
+
allowAlways: "always allow",
|
|
4228
|
+
deny: "Deny",
|
|
4229
|
+
required: "Permission required to run a tool",
|
|
4230
|
+
request: "Request:",
|
|
4231
|
+
tool: "Tool:",
|
|
4232
|
+
action: "Action:",
|
|
4233
|
+
parameters: "Parameters:",
|
|
4234
|
+
replyWith: "Reply with:"
|
|
4235
|
+
},
|
|
4236
|
+
zh: {
|
|
4237
|
+
toolUse: "\u5DE5\u5177\u8C03\u7528",
|
|
4238
|
+
allowOnce: "\u4EC5\u5141\u8BB8\u672C\u6B21",
|
|
4239
|
+
allowAlwaysProject: "\u59CB\u7EC8\u5141\u8BB8\u6B64\u9879\u76EE",
|
|
4240
|
+
allowAlwaysUser: "\u59CB\u7EC8\u5141\u8BB8\u6B64\u7528\u6237",
|
|
4241
|
+
allowAlways: "\u59CB\u7EC8\u5141\u8BB8",
|
|
4242
|
+
deny: "\u62D2\u7EDD",
|
|
4243
|
+
required: "\u8FD0\u884C\u5DE5\u5177\u9700\u8981\u6388\u6743",
|
|
4244
|
+
request: "\u8BF7\u6C42\uFF1A",
|
|
4245
|
+
tool: "\u5DE5\u5177\uFF1A",
|
|
4246
|
+
action: "\u64CD\u4F5C\uFF1A",
|
|
4247
|
+
parameters: "\u53C2\u6570\uFF1A",
|
|
4248
|
+
replyWith: "\u56DE\u590D\u4EE5\u4E0B\u547D\u4EE4\uFF1A"
|
|
4249
|
+
}
|
|
4250
|
+
};
|
|
4251
|
+
function localizedScopedAlwaysLabel(label, stockLabel, localizedLabel) {
|
|
4252
|
+
if (label === stockLabel)
|
|
4253
|
+
return localizedLabel;
|
|
4254
|
+
const scopeSeparator = ": ";
|
|
4255
|
+
if (!label.startsWith(stockLabel + scopeSeparator))
|
|
4256
|
+
return void 0;
|
|
4257
|
+
return `${localizedLabel}\uFF1A${label.slice(stockLabel.length + scopeSeparator.length)}`;
|
|
4258
|
+
}
|
|
4259
|
+
__name(localizedScopedAlwaysLabel, "localizedScopedAlwaysLabel");
|
|
3994
4260
|
var COMMAND_TOKEN_CHARS = "a-zA-Z0-9_:-";
|
|
3995
4261
|
var PARSE_COMMAND_RE = new RegExp(`^\\/([${COMMAND_TOKEN_CHARS}]+)(?:@\\S+)?\\s*(.*)`, "s");
|
|
3996
4262
|
var COMMAND_TOKEN_RE = new RegExp(`^[${COMMAND_TOKEN_CHARS}]+(?:@\\S+)?$`);
|
|
@@ -4034,6 +4300,7 @@ var ChannelBase = class {
|
|
|
4034
4300
|
proxy;
|
|
4035
4301
|
/** Adapter-owned persistent state directory, when supplied by the runtime. */
|
|
4036
4302
|
stateDir;
|
|
4303
|
+
locale;
|
|
4037
4304
|
channelMemory;
|
|
4038
4305
|
memoryIntentClassifier;
|
|
4039
4306
|
channelMemoryRecallObserver;
|
|
@@ -4088,6 +4355,9 @@ var ChannelBase = class {
|
|
|
4088
4355
|
bridgeSessionDiedListener = /* @__PURE__ */ __name((event) => {
|
|
4089
4356
|
this.onSessionDied(event.sessionId);
|
|
4090
4357
|
}, "bridgeSessionDiedListener");
|
|
4358
|
+
bridgeDisconnectedListener = /* @__PURE__ */ __name(() => {
|
|
4359
|
+
this.onBridgeDisconnected();
|
|
4360
|
+
}, "bridgeDisconnectedListener");
|
|
4091
4361
|
bridgePermissionRequestListener = /* @__PURE__ */ __name((event) => {
|
|
4092
4362
|
void this.dispatchPermissionRequest(event).catch((err) => {
|
|
4093
4363
|
process.stderr.write(`[${this.name}] permission relay failed for request ${sanitizeLogText(event.requestId, 128)}: ${this.lifecycleError(err)}
|
|
@@ -4364,6 +4634,10 @@ No answer is available from the current conversation context.`;
|
|
|
4364
4634
|
if (presentation && await presentation) {
|
|
4365
4635
|
return;
|
|
4366
4636
|
}
|
|
4637
|
+
const permissionPresentation = this.tryPresentPermission(pending);
|
|
4638
|
+
if (permissionPresentation && await permissionPresentation) {
|
|
4639
|
+
return;
|
|
4640
|
+
}
|
|
4367
4641
|
const text = this.formatPermissionRequest(pending);
|
|
4368
4642
|
if (target.threadId !== void 0 && this.supportsProactiveSend() && this.supportsProactiveTarget(target)) {
|
|
4369
4643
|
await this.pushProactive(target, text, pending.sourceLabel);
|
|
@@ -4444,6 +4718,103 @@ No answer is available from the current conversation context.`;
|
|
|
4444
4718
|
}
|
|
4445
4719
|
})();
|
|
4446
4720
|
}
|
|
4721
|
+
tryPresentPermission(pending) {
|
|
4722
|
+
const active = this.activePrompts.get(pending.sessionId);
|
|
4723
|
+
const toolCall = pending.request.toolCall;
|
|
4724
|
+
const meta = isRecord2(toolCall["_meta"]) ? toolCall["_meta"] : void 0;
|
|
4725
|
+
const isUserQuestion = meta?.["qwenInteractionKind"] === "user_question" || meta?.["toolName"] === "ask_user_question" || toolCall["kind"] === "ask_user_question";
|
|
4726
|
+
const decisions = this.permissionPresentationDecisions(pending);
|
|
4727
|
+
if (!active || active.loopPrompt || !active.owner || isUserQuestion || !decisions) {
|
|
4728
|
+
return void 0;
|
|
4729
|
+
}
|
|
4730
|
+
const precedingSegment = this.closeOutputSegment(pending.sessionId, active, pending.target);
|
|
4731
|
+
let respondInvoked = false;
|
|
4732
|
+
const context = {
|
|
4733
|
+
requestId: pending.requestId,
|
|
4734
|
+
sessionId: pending.sessionId,
|
|
4735
|
+
runId: active.runId,
|
|
4736
|
+
owner: active.owner,
|
|
4737
|
+
target: pending.target,
|
|
4738
|
+
...precedingSegment ? { precedingSegmentId: precedingSegment.segmentId } : {},
|
|
4739
|
+
title: this.permissionTitle(pending.request.toolCall),
|
|
4740
|
+
decisions,
|
|
4741
|
+
onSettled: /* @__PURE__ */ __name((listener) => {
|
|
4742
|
+
if (pending.settled) {
|
|
4743
|
+
listener(pending.settled);
|
|
4744
|
+
return () => {
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
pending.settlementListeners.add(listener);
|
|
4748
|
+
return () => {
|
|
4749
|
+
pending.settlementListeners.delete(listener);
|
|
4750
|
+
};
|
|
4751
|
+
}, "onSettled"),
|
|
4752
|
+
respond: /* @__PURE__ */ __name((decision) => {
|
|
4753
|
+
const response = this.permissionPresentationResponse(pending, decision);
|
|
4754
|
+
if (!response)
|
|
4755
|
+
return Promise.resolve(false);
|
|
4756
|
+
respondInvoked = true;
|
|
4757
|
+
return this.respondToUserInput(pending, response);
|
|
4758
|
+
}, "respond")
|
|
4759
|
+
};
|
|
4760
|
+
pending.permissionPresented = true;
|
|
4761
|
+
return (async () => {
|
|
4762
|
+
try {
|
|
4763
|
+
if (precedingSegment) {
|
|
4764
|
+
await this.notifyOutputSegmentEnd(pending.target.chatId, pending.sessionId, precedingSegment, "input_requested");
|
|
4765
|
+
}
|
|
4766
|
+
if (this.pendingPermissions.get(pending.requestId) !== pending) {
|
|
4767
|
+
return true;
|
|
4768
|
+
}
|
|
4769
|
+
const result = await this.presentPermissionRequest(context);
|
|
4770
|
+
if (this.pendingPermissions.get(pending.requestId) !== pending) {
|
|
4771
|
+
return true;
|
|
4772
|
+
}
|
|
4773
|
+
if (result.kind === "presented" || result.kind === "handled" && respondInvoked) {
|
|
4774
|
+
return true;
|
|
4775
|
+
}
|
|
4776
|
+
pending.permissionPresented = false;
|
|
4777
|
+
return false;
|
|
4778
|
+
} catch (err) {
|
|
4779
|
+
process.stderr.write(`[${this.name}] permission presentation failed for request ${sanitizeLogText(pending.requestId, 128)}: ${this.lifecycleError(err)}
|
|
4780
|
+
`);
|
|
4781
|
+
if (this.pendingPermissions.get(pending.requestId) !== pending) {
|
|
4782
|
+
return true;
|
|
4783
|
+
}
|
|
4784
|
+
pending.permissionPresented = false;
|
|
4785
|
+
return false;
|
|
4786
|
+
}
|
|
4787
|
+
})();
|
|
4788
|
+
}
|
|
4789
|
+
permissionPresentationDecisions(pending) {
|
|
4790
|
+
const allowOnce = this.approvalOption(pending);
|
|
4791
|
+
if (!allowOnce)
|
|
4792
|
+
return void 0;
|
|
4793
|
+
const copy = PERMISSION_COPY[this.locale];
|
|
4794
|
+
const allowAlways = this.approvalAlwaysOption(pending);
|
|
4795
|
+
return [
|
|
4796
|
+
{
|
|
4797
|
+
kind: "allow_once",
|
|
4798
|
+
label: sanitizeQuotedText(this.permissionOptionLabel(allowOnce, copy.allowOnce), 80)
|
|
4799
|
+
},
|
|
4800
|
+
...allowAlways ? [
|
|
4801
|
+
{
|
|
4802
|
+
kind: "allow_always",
|
|
4803
|
+
label: sanitizeQuotedText(allowAlways.label, 80)
|
|
4804
|
+
}
|
|
4805
|
+
] : [],
|
|
4806
|
+
{
|
|
4807
|
+
kind: "deny",
|
|
4808
|
+
label: sanitizeQuotedText(this.permissionOptionLabel(this.denialOption(pending), copy.deny), 80)
|
|
4809
|
+
}
|
|
4810
|
+
];
|
|
4811
|
+
}
|
|
4812
|
+
permissionPresentationResponse(pending, decision) {
|
|
4813
|
+
if (decision === "deny")
|
|
4814
|
+
return this.denialResponse(pending);
|
|
4815
|
+
const optionId = decision === "allow_once" ? this.approvalOptionId(pending) : this.approvalAlwaysOption(pending)?.optionId;
|
|
4816
|
+
return optionId ? { outcome: { outcome: "selected", optionId } } : void 0;
|
|
4817
|
+
}
|
|
4447
4818
|
normalizeUserQuestions(pending) {
|
|
4448
4819
|
const toolCall = pending.request.toolCall;
|
|
4449
4820
|
const meta = isRecord2(toolCall["_meta"]) ? toolCall["_meta"] : void 0;
|
|
@@ -4488,7 +4859,8 @@ No answer is available from the current conversation context.`;
|
|
|
4488
4859
|
}
|
|
4489
4860
|
async respondToUserInput(pending, response) {
|
|
4490
4861
|
if (pending.responsePromise) {
|
|
4491
|
-
|
|
4862
|
+
await pending.responsePromise;
|
|
4863
|
+
return false;
|
|
4492
4864
|
}
|
|
4493
4865
|
if (this.pendingPermissions.get(pending.requestId) !== pending || !this.bridge.respondToPermission) {
|
|
4494
4866
|
return false;
|
|
@@ -4541,6 +4913,7 @@ No answer is available from the current conversation context.`;
|
|
|
4541
4913
|
this.config = config;
|
|
4542
4914
|
this.messagePrefix = config.messagePrefix?.trim() || void 0;
|
|
4543
4915
|
this.bridge = bridge;
|
|
4916
|
+
this.locale = options?.locale ?? "en";
|
|
4544
4917
|
this.proxy = options?.proxy;
|
|
4545
4918
|
this.stateDir = options?.stateDir;
|
|
4546
4919
|
this.identity = Object.freeze(this.resolveIdentity(name, config));
|
|
@@ -4603,6 +4976,9 @@ No answer is available from the current conversation context.`;
|
|
|
4603
4976
|
async presentUserInputRequest(_context) {
|
|
4604
4977
|
return { kind: "unsupported" };
|
|
4605
4978
|
}
|
|
4979
|
+
async presentPermissionRequest(_context) {
|
|
4980
|
+
return { kind: "unsupported" };
|
|
4981
|
+
}
|
|
4606
4982
|
emitTaskLifecycle(event) {
|
|
4607
4983
|
try {
|
|
4608
4984
|
const result = this.onTaskLifecycle(event);
|
|
@@ -5495,7 +5871,6 @@ ${promptText}` : promptText;
|
|
|
5495
5871
|
return false;
|
|
5496
5872
|
}
|
|
5497
5873
|
active.cancelled = true;
|
|
5498
|
-
this.stopActiveStreaming(active, sessionId, reason);
|
|
5499
5874
|
this.dropCollectBuffer(sessionId);
|
|
5500
5875
|
this.removePendingPermissionsForSession(sessionId, "run_cancelled");
|
|
5501
5876
|
this.emitTaskCancellation(active, sessionId, reason);
|
|
@@ -5570,12 +5945,21 @@ ${promptText}` : promptText;
|
|
|
5570
5945
|
this.unattendedMemorySessions.delete(sessionId);
|
|
5571
5946
|
this.removePendingPermissionsForSession(sessionId);
|
|
5572
5947
|
}
|
|
5948
|
+
/**
|
|
5949
|
+
* Called when the standalone ACP bridge process exits. Its in-flight turns
|
|
5950
|
+
* never settle, but crash recovery restores the sessions on a fresh bridge,
|
|
5951
|
+
* so overrides must clear only turn-scoped transient state (never session
|
|
5952
|
+
* routing) and must not fabricate terminal outcomes for interrupted turns.
|
|
5953
|
+
*/
|
|
5954
|
+
onBridgeDisconnected() {
|
|
5955
|
+
}
|
|
5573
5956
|
onSessionRetiring(_sessionId) {
|
|
5574
5957
|
}
|
|
5575
5958
|
attachBridgeEvents(bridge) {
|
|
5576
5959
|
bridge.on("toolCall", this.bridgeToolCallListener);
|
|
5577
5960
|
bridge.on("backgroundResponse", this.bridgeBackgroundResponseListener);
|
|
5578
5961
|
bridge.on("sessionDied", this.bridgeSessionDiedListener);
|
|
5962
|
+
bridge.on("disconnected", this.bridgeDisconnectedListener);
|
|
5579
5963
|
bridge.on("permissionRequest", this.bridgePermissionRequestListener);
|
|
5580
5964
|
bridge.on("permissionResolved", this.bridgePermissionResolvedListener);
|
|
5581
5965
|
}
|
|
@@ -5583,6 +5967,7 @@ ${promptText}` : promptText;
|
|
|
5583
5967
|
bridge.off("toolCall", this.bridgeToolCallListener);
|
|
5584
5968
|
bridge.off("backgroundResponse", this.bridgeBackgroundResponseListener);
|
|
5585
5969
|
bridge.off("sessionDied", this.bridgeSessionDiedListener);
|
|
5970
|
+
bridge.off("disconnected", this.bridgeDisconnectedListener);
|
|
5586
5971
|
bridge.off("permissionRequest", this.bridgePermissionRequestListener);
|
|
5587
5972
|
bridge.off("permissionResolved", this.bridgePermissionResolvedListener);
|
|
5588
5973
|
}
|
|
@@ -5792,14 +6177,15 @@ ${promptText}` : promptText;
|
|
|
5792
6177
|
return { kind: "found", pending: matching[0] };
|
|
5793
6178
|
}
|
|
5794
6179
|
canEnvelopeAnswerPendingPermission(envelope, pending) {
|
|
5795
|
-
return pending.target.chatId === envelope.chatId && pending.target.threadId === envelope.threadId && (!pending.userInputPresented || pending.target.senderId === envelope.senderId) && (this.isSharedSessionTarget(pending.target) || pending.target.senderId === envelope.senderId);
|
|
6180
|
+
return pending.target.chatId === envelope.chatId && pending.target.threadId === envelope.threadId && (!pending.userInputPresented && !pending.permissionPresented || pending.target.senderId === envelope.senderId) && (this.isSharedSessionTarget(pending.target) || pending.target.senderId === envelope.senderId);
|
|
5796
6181
|
}
|
|
5797
6182
|
formatPermissionRequest(pending) {
|
|
5798
6183
|
const { toolCall } = pending.request;
|
|
6184
|
+
const copy = PERMISSION_COPY[this.locale];
|
|
5799
6185
|
const parameters = this.permissionParameterSummary(toolCall);
|
|
5800
|
-
const approveLabel = this.permissionOptionLabel(this.approvalOption(pending),
|
|
6186
|
+
const approveLabel = this.permissionOptionLabel(this.approvalOption(pending), copy.allowOnce.toLocaleLowerCase(this.locale));
|
|
5801
6187
|
const alwaysOption = this.approvalAlwaysOption(pending);
|
|
5802
|
-
const denyLabel = this.permissionOptionLabel(this.denialOption(pending),
|
|
6188
|
+
const denyLabel = this.permissionOptionLabel(this.denialOption(pending), copy.deny.toLocaleLowerCase(this.locale));
|
|
5803
6189
|
const requestSuffix = pending.taskName ? ` ${pending.requestId}` : "";
|
|
5804
6190
|
const replyPadding = pending.taskName ? { approve: " ", always: " ", deny: " " } : { approve: " ", always: " ", deny: " " };
|
|
5805
6191
|
const replies = [
|
|
@@ -5810,14 +6196,14 @@ ${promptText}` : promptText;
|
|
|
5810
6196
|
`${this.prefixedCommand(`/deny${requestSuffix}`)}${replyPadding.deny}${denyLabel}`
|
|
5811
6197
|
];
|
|
5812
6198
|
return [
|
|
5813
|
-
|
|
5814
|
-
...pending.taskName ? [
|
|
6199
|
+
copy.required,
|
|
6200
|
+
...pending.taskName ? [`${copy.request} ${pending.requestId}`] : [],
|
|
5815
6201
|
"",
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
...parameters ? [
|
|
6202
|
+
`${copy.tool} ${this.permissionToolName(toolCall)}`,
|
|
6203
|
+
`${copy.action} ${this.permissionTitle(toolCall)}`,
|
|
6204
|
+
...parameters ? [`${copy.parameters} ${parameters}`] : [],
|
|
5819
6205
|
"",
|
|
5820
|
-
|
|
6206
|
+
copy.replyWith,
|
|
5821
6207
|
...replies
|
|
5822
6208
|
].join("\n");
|
|
5823
6209
|
}
|
|
@@ -5829,7 +6215,7 @@ ${promptText}` : promptText;
|
|
|
5829
6215
|
}
|
|
5830
6216
|
permissionTitle(toolCall) {
|
|
5831
6217
|
const rawTitle = typeof toolCall.title === "string" ? toolCall.title : void 0;
|
|
5832
|
-
return sanitizeQuotedText(rawTitle || "", 160).trim() ||
|
|
6218
|
+
return sanitizeQuotedText(rawTitle || "", 160).trim() || PERMISSION_COPY[this.locale].toolUse;
|
|
5833
6219
|
}
|
|
5834
6220
|
permissionToolName(toolCall) {
|
|
5835
6221
|
const rawToolCall = toolCall;
|
|
@@ -5869,7 +6255,31 @@ ${promptText}` : promptText;
|
|
|
5869
6255
|
permissionOptionLabel(option, fallback) {
|
|
5870
6256
|
const rawLabel = typeof option?.name === "string" ? option.name : "";
|
|
5871
6257
|
const label = sanitizeQuotedText(rawLabel, 160).trim();
|
|
5872
|
-
|
|
6258
|
+
if (!label)
|
|
6259
|
+
return fallback;
|
|
6260
|
+
return this.localizedPermissionOptionLabel(option, label) ?? label;
|
|
6261
|
+
}
|
|
6262
|
+
localizedPermissionOptionLabel(option, label) {
|
|
6263
|
+
if (this.locale !== "zh")
|
|
6264
|
+
return void 0;
|
|
6265
|
+
const copy = PERMISSION_COPY[this.locale];
|
|
6266
|
+
if (option?.kind === "allow_always") {
|
|
6267
|
+
if (option.optionId === "proceed_always_project") {
|
|
6268
|
+
return localizedScopedAlwaysLabel(label, "Always Allow in project", copy.allowAlwaysProject);
|
|
6269
|
+
}
|
|
6270
|
+
if (option.optionId === "proceed_always_user") {
|
|
6271
|
+
return localizedScopedAlwaysLabel(label, "Always Allow for user", copy.allowAlwaysUser);
|
|
6272
|
+
}
|
|
6273
|
+
if (option.optionId === "proceed_always" && label === "Allow All Edits") {
|
|
6274
|
+
return copy.allowAlways;
|
|
6275
|
+
}
|
|
6276
|
+
return void 0;
|
|
6277
|
+
}
|
|
6278
|
+
if (label === "Allow" || label === "Allow once")
|
|
6279
|
+
return copy.allowOnce;
|
|
6280
|
+
if (label === "Deny" || label === "Reject")
|
|
6281
|
+
return copy.deny;
|
|
6282
|
+
return void 0;
|
|
5873
6283
|
}
|
|
5874
6284
|
approvalOption(pending) {
|
|
5875
6285
|
const options = pending.request.options;
|
|
@@ -5893,13 +6303,14 @@ ${promptText}` : promptText;
|
|
|
5893
6303
|
return options.find((option) => option.optionId === `proceed_always_${scope}`);
|
|
5894
6304
|
}
|
|
5895
6305
|
approvalAlwaysLabel(option) {
|
|
6306
|
+
const copy = PERMISSION_COPY[this.locale];
|
|
5896
6307
|
if (option.optionId === "proceed_always_project") {
|
|
5897
|
-
return
|
|
6308
|
+
return copy.allowAlwaysProject;
|
|
5898
6309
|
}
|
|
5899
6310
|
if (option.optionId === "proceed_always_user") {
|
|
5900
|
-
return
|
|
6311
|
+
return copy.allowAlwaysUser;
|
|
5901
6312
|
}
|
|
5902
|
-
return
|
|
6313
|
+
return copy.allowAlways;
|
|
5903
6314
|
}
|
|
5904
6315
|
denialResponse(pending) {
|
|
5905
6316
|
const option = this.denialOption(pending);
|
|
@@ -5965,7 +6376,7 @@ ${requestList}`);
|
|
|
5965
6376
|
}
|
|
5966
6377
|
let accepted;
|
|
5967
6378
|
try {
|
|
5968
|
-
accepted = pending.userInputPresented ? await this.respondToUserInput(pending, response) : await this.bridge.respondToPermission(pending.requestId, response);
|
|
6379
|
+
accepted = pending.userInputPresented || pending.permissionPresented ? await this.respondToUserInput(pending, response) : await this.bridge.respondToPermission(pending.requestId, response);
|
|
5969
6380
|
} catch (err) {
|
|
5970
6381
|
this.removePendingPermission(pending.requestId);
|
|
5971
6382
|
process.stderr.write(`[${this.name}] permission response failed for request ${sanitizeLogText(pending.requestId, 128)}: ${this.lifecycleError(err)}
|
|
@@ -6020,6 +6431,21 @@ ${requestList}`);
|
|
|
6020
6431
|
binding.released = true;
|
|
6021
6432
|
this.releaseQueuedTurn(binding.sessionId);
|
|
6022
6433
|
}
|
|
6434
|
+
/**
|
|
6435
|
+
* Follow a task onto the session its reload healed to (a superseded
|
|
6436
|
+
* redirect). The queue reservation and the staleness generation are keyed
|
|
6437
|
+
* by session id, so both must move with the binding: leaving them behind
|
|
6438
|
+
* keeps the stale id "busy" forever and drops the turn on a generation the
|
|
6439
|
+
* replacement never had.
|
|
6440
|
+
*/
|
|
6441
|
+
moveNamedTurnBinding(binding, sessionId) {
|
|
6442
|
+
if (binding.sessionId !== null) {
|
|
6443
|
+
this.releaseQueuedTurn(binding.sessionId);
|
|
6444
|
+
}
|
|
6445
|
+
binding.sessionId = sessionId;
|
|
6446
|
+
binding.generation = this.sessionGenerations.get(sessionId) ?? 0;
|
|
6447
|
+
this.reserveQueuedTurn(sessionId);
|
|
6448
|
+
}
|
|
6023
6449
|
finishNamedTurnBinding(envelope) {
|
|
6024
6450
|
const binding = this.namedTurnBindings.get(envelope);
|
|
6025
6451
|
if (!binding)
|
|
@@ -6075,12 +6501,51 @@ ${requestList}`);
|
|
|
6075
6501
|
return true;
|
|
6076
6502
|
}
|
|
6077
6503
|
}
|
|
6504
|
+
/**
|
|
6505
|
+
* The actionable recovery message for a worktree task whose ownership state
|
|
6506
|
+
* the daemon refused to restore. Both codes come from the load/resume route
|
|
6507
|
+
* — the reset route resumes an interrupted transfer itself and reports a
|
|
6508
|
+
* broken marker as invalid state — so they surface on selection and on a
|
|
6509
|
+
* message, wrapped in the manager's generic load failure.
|
|
6510
|
+
*
|
|
6511
|
+
* Clearing always acts on the *selected* task, so pointing the user at a
|
|
6512
|
+
* clear is only safe when the task that failed is the selected one. Aimed at
|
|
6513
|
+
* any other task it would run a full ownership transfer against a healthy
|
|
6514
|
+
* one and destroy that conversation, so the alternative points at the close
|
|
6515
|
+
* that works on the broken task without loading it. Both name that task.
|
|
6516
|
+
*/
|
|
6517
|
+
async worktreeRecoveryMessage(envelope, error) {
|
|
6518
|
+
const code = readDaemonHttpErrorCode(error);
|
|
6519
|
+
if (code !== "worktree_reset_interrupted" && code !== "worktree_marker_missing") {
|
|
6520
|
+
return void 0;
|
|
6521
|
+
}
|
|
6522
|
+
const interrupted = code === "worktree_reset_interrupted";
|
|
6523
|
+
const failedTaskName = error instanceof NamedSessionTaskError ? error.taskName : void 0;
|
|
6524
|
+
const safeTaskName = failedTaskName === void 0 ? void 0 : sanitizeDisplayText(failedTaskName, 32);
|
|
6525
|
+
const subject = safeTaskName === void 0 ? "The task" : `Task "${safeTaskName}"`;
|
|
6526
|
+
const problem = interrupted ? "was interrupted while being reset" : "cannot verify its worktree because its ownership marker is missing";
|
|
6527
|
+
if (safeTaskName !== void 0 && failedTaskName === await this.selectedTaskName(envelope)) {
|
|
6528
|
+
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."}`;
|
|
6529
|
+
}
|
|
6530
|
+
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}`)}`;
|
|
6531
|
+
return `${subject} ${problem}. Its files were not changed. Clearing now would reset the selected task instead, so ${remedy}.`;
|
|
6532
|
+
}
|
|
6533
|
+
async selectedTaskName(envelope) {
|
|
6534
|
+
const namedSessions = this.namedSessions;
|
|
6535
|
+
if (!namedSessions)
|
|
6536
|
+
return void 0;
|
|
6537
|
+
try {
|
|
6538
|
+
return (await namedSessions.current(this.namedSessionOwner(envelope)))?.name;
|
|
6539
|
+
} catch {
|
|
6540
|
+
return void 0;
|
|
6541
|
+
}
|
|
6542
|
+
}
|
|
6078
6543
|
async sendNamedSessionError(envelope, error) {
|
|
6079
6544
|
if (error instanceof Error && error.cause !== void 0) {
|
|
6080
6545
|
process.stderr.write(`[${sanitizeLogText(this.name, 64)}] named-session operation failed: ${this.lifecycleError(error)} | cause: ${this.lifecycleError(error.cause)}
|
|
6081
6546
|
`);
|
|
6082
6547
|
}
|
|
6083
|
-
const message = error instanceof Error ? sanitizeDisplayText(error.message, 500) : "Named-session operation failed.";
|
|
6548
|
+
const message = await this.worktreeRecoveryMessage(envelope, error) ?? (error instanceof Error ? sanitizeDisplayText(error.message, 500) : "Named-session operation failed.");
|
|
6084
6549
|
await this.sendThreadMessage(envelope.chatId, envelope.threadId, message || "Named-session operation failed.");
|
|
6085
6550
|
}
|
|
6086
6551
|
async handleNamedSessionsCommand(envelope, args) {
|
|
@@ -6125,7 +6590,7 @@ ${requestList}`);
|
|
|
6125
6590
|
}
|
|
6126
6591
|
case "new": {
|
|
6127
6592
|
const isolation = parts.length === 2 && parts[1] === "--worktree" ? "worktree" : "shared";
|
|
6128
|
-
if (isolation === "shared" && parts.length !== 1 || isolation === "worktree" && parts.length !== 2) {
|
|
6593
|
+
if (isolation === "shared" && parts.length !== 1 || isolation === "worktree" && parts.length !== 2 || parts[0]?.startsWith("-")) {
|
|
6129
6594
|
break;
|
|
6130
6595
|
}
|
|
6131
6596
|
const created = await namedSessions.create(owner, parts[0], isolation);
|
|
@@ -6186,6 +6651,7 @@ ${requestList}`);
|
|
|
6186
6651
|
registerSharedCommands() {
|
|
6187
6652
|
const doClear = /* @__PURE__ */ __name(async (envelope) => {
|
|
6188
6653
|
let resetTaskName;
|
|
6654
|
+
let resetWorktreeKept = false;
|
|
6189
6655
|
let removedIds;
|
|
6190
6656
|
const retiringSessionId = this.namedSessions ? void 0 : this.router.getSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
|
|
6191
6657
|
if (retiringSessionId)
|
|
@@ -6194,8 +6660,18 @@ ${requestList}`);
|
|
|
6194
6660
|
try {
|
|
6195
6661
|
const reset = await this.namedSessions.reset(this.namedSessionOwner(envelope));
|
|
6196
6662
|
resetTaskName = reset?.name;
|
|
6663
|
+
resetWorktreeKept = reset?.worktreeKept ?? false;
|
|
6197
6664
|
removedIds = reset ? [reset.previousSessionId] : [];
|
|
6198
6665
|
} catch (error) {
|
|
6666
|
+
const code = readDaemonHttpErrorCode(error);
|
|
6667
|
+
if (code !== void 0) {
|
|
6668
|
+
process.stderr.write(`[${sanitizeLogText(this.name, 64)}] worktree reset failed (${sanitizeLogText(code, 64)}): ${this.lifecycleError(error)}
|
|
6669
|
+
`);
|
|
6670
|
+
}
|
|
6671
|
+
if (code === "worktree_reset_active") {
|
|
6672
|
+
await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Task is busy. Wait for the running prompt to finish (or cancel it), then try again.");
|
|
6673
|
+
return;
|
|
6674
|
+
}
|
|
6199
6675
|
await this.sendNamedSessionError(envelope, error);
|
|
6200
6676
|
return;
|
|
6201
6677
|
}
|
|
@@ -6250,7 +6726,7 @@ ${requestList}`);
|
|
|
6250
6726
|
}
|
|
6251
6727
|
this.discardRetiredSession(this.bridge, id, "cleared");
|
|
6252
6728
|
}
|
|
6253
|
-
await this.sendThreadMessage(envelope.chatId, envelope.threadId, resetTaskName ? `Task "${resetTaskName}" reset with a fresh conversation.` : "Session cleared. The next message starts a fresh conversation.");
|
|
6729
|
+
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.");
|
|
6254
6730
|
} else {
|
|
6255
6731
|
await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No active session to clear.");
|
|
6256
6732
|
}
|
|
@@ -7212,17 +7688,8 @@ ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id
|
|
|
7212
7688
|
const active = this.activePrompts.get(sessionId);
|
|
7213
7689
|
return active?.senderName || active?.senderId || target.senderId || "agent";
|
|
7214
7690
|
}
|
|
7215
|
-
stopActiveStreaming(active, sessionId, reason) {
|
|
7216
|
-
try {
|
|
7217
|
-
active.stopStreaming?.();
|
|
7218
|
-
} catch (err) {
|
|
7219
|
-
process.stderr.write(`[${this.name}] stopStreaming threw during ${reason} for session ${sessionId}: ${err instanceof Error ? err.message : err}
|
|
7220
|
-
`);
|
|
7221
|
-
}
|
|
7222
|
-
}
|
|
7223
7691
|
/**
|
|
7224
|
-
* Cancel the active turn and wait (bounded) for it to wind down.
|
|
7225
|
-
* BlockStreamer so buffered text can't leak via the idle timer, then fires a
|
|
7692
|
+
* Cancel the active turn and wait (bounded) for it to wind down. Fires a
|
|
7226
7693
|
* best-effort cancelSession (NOT awaited — a wedged child/daemon can leave the
|
|
7227
7694
|
* request pending forever). Returns true if active.done settled first, false
|
|
7228
7695
|
* if the CLEAR_CANCEL_TIMEOUT_MS bound won (the turn never wound down). Used by
|
|
@@ -7233,7 +7700,6 @@ ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id
|
|
|
7233
7700
|
*/
|
|
7234
7701
|
async cancelAndAwaitActive(active, sessionId) {
|
|
7235
7702
|
active.cancelled = true;
|
|
7236
|
-
this.stopActiveStreaming(active, sessionId, "cancel");
|
|
7237
7703
|
void this.bridge.cancelSession(sessionId).catch((err) => {
|
|
7238
7704
|
process.stderr.write(`[${this.name}] cancelSession failed for session=${sessionId} (clear/await): ${err instanceof Error ? err.message : err}
|
|
7239
7705
|
`);
|
|
@@ -7775,8 +8241,10 @@ ${text}`;
|
|
|
7775
8241
|
return;
|
|
7776
8242
|
}
|
|
7777
8243
|
try {
|
|
7778
|
-
|
|
7779
|
-
sessionId
|
|
8244
|
+
sessionId = await this.namedSessions.resumeReserved(this.namedSessionOwner(envelope), namedTurn.sessionId);
|
|
8245
|
+
if (sessionId && sessionId !== namedTurn.sessionId) {
|
|
8246
|
+
this.moveNamedTurnBinding(namedTurn, sessionId);
|
|
8247
|
+
}
|
|
7780
8248
|
} catch (error) {
|
|
7781
8249
|
await this.sendNamedSessionError(envelope, error);
|
|
7782
8250
|
return;
|
|
@@ -7921,7 +8389,6 @@ ${promptText}`;
|
|
|
7921
8389
|
if (firstCancellation) {
|
|
7922
8390
|
process.stderr.write(`[${this.name}] steer: cancelled active turn for ${envelope.senderId} in session ${sessionId}
|
|
7923
8391
|
`);
|
|
7924
|
-
this.stopActiveStreaming(active, sessionId, "steer");
|
|
7925
8392
|
void this.bridge.cancelSession(sessionId).catch((err) => {
|
|
7926
8393
|
process.stderr.write(`[${this.name}] cancelSession failed for session=${sessionId} (steer): ${err instanceof Error ? err.message : err}
|
|
7927
8394
|
`);
|
|
@@ -7956,7 +8423,6 @@ ${promptText}`;
|
|
|
7956
8423
|
}
|
|
7957
8424
|
const prev = this.sessionQueues.get(sessionId) ?? Promise.resolve();
|
|
7958
8425
|
const generation = namedTurn?.generation ?? this.sessionGenerations.get(sessionId) ?? 0;
|
|
7959
|
-
const useBlockStreaming = this.config.blockStreaming === "on";
|
|
7960
8426
|
if (namedTurn) {
|
|
7961
8427
|
namedTurn.claimed = true;
|
|
7962
8428
|
} else {
|
|
@@ -8059,18 +8525,9 @@ ${promptToSend}`;
|
|
|
8059
8525
|
process.stderr.write(`[${this.name}] onPromptStart threw for session ${sessionId}: ${this.lifecycleError(err)}
|
|
8060
8526
|
`);
|
|
8061
8527
|
}
|
|
8062
|
-
const streamer = useBlockStreaming ? new BlockStreamer({
|
|
8063
|
-
minChars: this.config.blockStreamingChunk?.minChars ?? 400,
|
|
8064
|
-
maxChars: this.config.blockStreamingChunk?.maxChars ?? 1e3,
|
|
8065
|
-
idleMs: this.config.blockStreamingCoalesce?.idleMs ?? 1500,
|
|
8066
|
-
send: /* @__PURE__ */ __name((text) => this.sendResponseMessage(envelope.chatId, text, sessionId, sourceLabel), "send")
|
|
8067
|
-
}) : null;
|
|
8068
|
-
promptState.stopStreaming = () => streamer?.stop();
|
|
8069
8528
|
const heldChunks = [];
|
|
8070
|
-
let hasStreamedText = false;
|
|
8071
8529
|
const releaseHeldChunks = /* @__PURE__ */ __name(() => {
|
|
8072
8530
|
for (const held of heldChunks.splice(0)) {
|
|
8073
|
-
hasStreamedText = true;
|
|
8074
8531
|
const segment = this.ensureOutputSegment(sessionId, promptState);
|
|
8075
8532
|
this.emitTaskLifecycle({
|
|
8076
8533
|
...this.lifecycleBase(envelope.chatId, sessionId, envelope.messageId),
|
|
@@ -8078,7 +8535,6 @@ ${promptToSend}`;
|
|
|
8078
8535
|
chunk: held
|
|
8079
8536
|
});
|
|
8080
8537
|
this.onResponseChunk(envelope.chatId, held, sessionId, segment);
|
|
8081
|
-
streamer?.push(held);
|
|
8082
8538
|
}
|
|
8083
8539
|
}, "releaseHeldChunks");
|
|
8084
8540
|
const onChunk = /* @__PURE__ */ __name((sid, chunk) => {
|
|
@@ -8095,10 +8551,8 @@ ${promptToSend}`;
|
|
|
8095
8551
|
return;
|
|
8096
8552
|
}
|
|
8097
8553
|
heldChunks.length = 0;
|
|
8098
|
-
hasStreamedText = false;
|
|
8099
8554
|
const segment = this.closeOutputSegment(sessionId, promptState);
|
|
8100
8555
|
void this.notifyOutputSegmentEnd(envelope.chatId, sessionId, segment, "response_boundary");
|
|
8101
|
-
streamer?.stop();
|
|
8102
8556
|
}, "onResponseBoundary");
|
|
8103
8557
|
await this.waitForBridgeRecovery();
|
|
8104
8558
|
const promptBridge = this.bridge;
|
|
@@ -8117,17 +8571,10 @@ ${promptToSend}`;
|
|
|
8117
8571
|
}
|
|
8118
8572
|
if (!promptState.cancelled && response) {
|
|
8119
8573
|
promptState.deliveryStarted = true;
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
await streamer.flush();
|
|
8125
|
-
} else {
|
|
8126
|
-
const segment = this.ensureOutputSegment(sessionId, promptState);
|
|
8127
|
-
await this.onResponseComplete(envelope.chatId, response, sessionId, segment);
|
|
8128
|
-
if (segment && promptState.activeSegmentId === segment.segmentId) {
|
|
8129
|
-
promptState.activeSegmentId = void 0;
|
|
8130
|
-
}
|
|
8574
|
+
const segment = this.ensureOutputSegment(sessionId, promptState);
|
|
8575
|
+
await this.onResponseComplete(envelope.chatId, response, sessionId, segment);
|
|
8576
|
+
if (segment && promptState.activeSegmentId === segment.segmentId) {
|
|
8577
|
+
promptState.activeSegmentId = void 0;
|
|
8131
8578
|
}
|
|
8132
8579
|
}
|
|
8133
8580
|
if (!promptState.deliveryStarted) {
|
|
@@ -8172,10 +8619,6 @@ ${promptToSend}`;
|
|
|
8172
8619
|
} finally {
|
|
8173
8620
|
promptBridge.off("textChunk", onChunk);
|
|
8174
8621
|
promptBridge.off("responseBoundary", onResponseBoundary);
|
|
8175
|
-
if (streamer) {
|
|
8176
|
-
streamer.stop();
|
|
8177
|
-
await streamer.drain();
|
|
8178
|
-
}
|
|
8179
8622
|
const stillCurrent = this.activePrompts.get(sessionId) === promptState;
|
|
8180
8623
|
if (!promptState.clearEvicted) {
|
|
8181
8624
|
try {
|
|
@@ -8489,6 +8932,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
8489
8932
|
activePrompts = /* @__PURE__ */ new Set();
|
|
8490
8933
|
activePromptControllers = /* @__PURE__ */ new Map();
|
|
8491
8934
|
availableCommandsBySession = /* @__PURE__ */ new Map();
|
|
8935
|
+
toolCallKindsBySession = /* @__PURE__ */ new Map();
|
|
8492
8936
|
turnBarriers = /* @__PURE__ */ new Map();
|
|
8493
8937
|
channelLoopToolHandlers = [];
|
|
8494
8938
|
channelLoopDisabledSessions = /* @__PURE__ */ new Set();
|
|
@@ -8595,6 +9039,38 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
8595
9039
|
}
|
|
8596
9040
|
return session.sessionId;
|
|
8597
9041
|
}
|
|
9042
|
+
/**
|
|
9043
|
+
* Transfer a worktree session's checkout ownership to a fresh replacement
|
|
9044
|
+
* session (daemon `session_worktree_reset_v1`). The returned id is the
|
|
9045
|
+
* replacement's; the superseded session's clients stay bound to it (and
|
|
9046
|
+
* are forgotten by the caller). Gated on the capability flag so a daemon
|
|
9047
|
+
* without reset support fails before any session is created.
|
|
9048
|
+
*/
|
|
9049
|
+
async resetWorktreeSession(sessionId, cwd, options, bindingToken) {
|
|
9050
|
+
if (!this.options.sessionWorktreeReset) {
|
|
9051
|
+
throw new Error("The daemon does not support worktree reset for Channel tasks.");
|
|
9052
|
+
}
|
|
9053
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
9054
|
+
const session = await this.options.sessionFactory({
|
|
9055
|
+
workspaceCwd: cwd || this.options.cwd,
|
|
9056
|
+
modelServiceId: this.options.modelServiceId,
|
|
9057
|
+
sessionScope: this.options.sessionScope ?? "thread",
|
|
9058
|
+
...options?.approvalMode ? { approvalMode: options.approvalMode } : {},
|
|
9059
|
+
...options?.sourceId ? { sourceId: options.sourceId } : {},
|
|
9060
|
+
worktreeReset: { sessionId }
|
|
9061
|
+
});
|
|
9062
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) {
|
|
9063
|
+
await this.rejectStaleSession(session);
|
|
9064
|
+
}
|
|
9065
|
+
this.attachSession(session, bindingToken);
|
|
9066
|
+
if (options?.enableChannelLoops === false) {
|
|
9067
|
+
this.channelLoopDisabledSessions.add(session.sessionId);
|
|
9068
|
+
void this.reconcileChannelLoopMcpForSession(session.sessionId);
|
|
9069
|
+
} else {
|
|
9070
|
+
await this.reconcileChannelLoopMcpForSession(session.sessionId);
|
|
9071
|
+
}
|
|
9072
|
+
return session.sessionId;
|
|
9073
|
+
}
|
|
8598
9074
|
registerChannelLoopToolHandler(handler) {
|
|
8599
9075
|
if (!this.channelLoopToolHandlers.includes(handler)) {
|
|
8600
9076
|
this.channelLoopToolHandlers.push(handler);
|
|
@@ -9001,15 +9477,23 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
9001
9477
|
case "tool_call":
|
|
9002
9478
|
case "tool_call_update": {
|
|
9003
9479
|
const toolCallId = getString(update["toolCallId"]);
|
|
9004
|
-
const
|
|
9480
|
+
const explicitKind = getString(update["kind"]);
|
|
9005
9481
|
const meta = isRecord3(update["_meta"]) ? update["_meta"] : void 0;
|
|
9006
|
-
if (!
|
|
9482
|
+
if (!explicitKind && toolCallId && getString(update["status"]) === "in_progress" && (meta?.["shellProgress"] !== void 0 || meta?.["subagentProgress"] === true)) {
|
|
9007
9483
|
break;
|
|
9008
9484
|
}
|
|
9485
|
+
let sessionKinds = this.toolCallKindsBySession.get(sessionId);
|
|
9486
|
+
const kind = explicitKind || sessionKinds?.get(toolCallId ?? "");
|
|
9009
9487
|
if (!toolCallId || !kind) {
|
|
9010
9488
|
this.emitProtocolError(`Malformed daemon ${type} event`, update);
|
|
9011
9489
|
break;
|
|
9012
9490
|
}
|
|
9491
|
+
if (type === "tool_call" || explicitKind) {
|
|
9492
|
+
const kinds = sessionKinds ?? /* @__PURE__ */ new Map();
|
|
9493
|
+
kinds.set(toolCallId, kind);
|
|
9494
|
+
this.toolCallKindsBySession.set(sessionId, kinds);
|
|
9495
|
+
sessionKinds = kinds;
|
|
9496
|
+
}
|
|
9013
9497
|
const event = {
|
|
9014
9498
|
sessionId,
|
|
9015
9499
|
toolCallId,
|
|
@@ -9022,6 +9506,12 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
9022
9506
|
this.emitResponseBoundary(sessionId);
|
|
9023
9507
|
}
|
|
9024
9508
|
this.emit("toolCall", event);
|
|
9509
|
+
if (event.status === "completed" || event.status === "failed") {
|
|
9510
|
+
sessionKinds?.delete(toolCallId);
|
|
9511
|
+
if (sessionKinds?.size === 0) {
|
|
9512
|
+
this.toolCallKindsBySession.delete(sessionId);
|
|
9513
|
+
}
|
|
9514
|
+
}
|
|
9025
9515
|
break;
|
|
9026
9516
|
}
|
|
9027
9517
|
case "plan": {
|
|
@@ -9149,6 +9639,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
9149
9639
|
this.abortActivePrompts(sessionId);
|
|
9150
9640
|
this.activePrompts.delete(sessionId);
|
|
9151
9641
|
this.availableCommandsBySession.delete(sessionId);
|
|
9642
|
+
this.toolCallKindsBySession.delete(sessionId);
|
|
9152
9643
|
if (this.latestAvailableCommandsSessionId === sessionId) {
|
|
9153
9644
|
this.latestAvailableCommandsSessionId = Array.from(this.availableCommandsBySession.keys()).at(-1);
|
|
9154
9645
|
}
|