@qwen-code/qwen-code 0.21.13 → 0.21.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/qc-helper/docs/configuration/settings.md +13 -7
- package/bundled/qc-helper/docs/features/code-review.md +5 -1
- package/bundled/qc-helper/docs/features/commands.md +120 -8
- package/bundled/qc-helper/docs/features/sub-agents.md +2 -2
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +20 -3
- package/bundled/review/SKILL.md +50 -30
- package/chunks/{MaxSizedBox-UQALOVVT.js → MaxSizedBox-67IDQILY.js} +24 -23
- package/chunks/{StandaloneSessionPicker-KEGXNUG6.js → StandaloneSessionPicker-G4QJIRMH.js} +41 -40
- package/chunks/{acp-startup-profiler-NMDXYGDN.js → acp-startup-profiler-HUYGO57H.js} +2 -2
- package/chunks/{acpAgent-XPES32S7.js → acpAgent-BS3YYO33.js} +626 -141
- package/chunks/{agent-DPTOZFEM.js → agent-EHHEXKWN.js} +22 -21
- package/chunks/{agent-headless-GJCQMURW.js → agent-headless-UT2ZF76T.js} +22 -21
- package/chunks/{anthropicContentGenerator-G7BVXTKN.js → anthropicContentGenerator-M7XRJMSK.js} +3 -3
- package/chunks/{bridge-YNQBAA4Z.js → bridge-WQ4IL2RF.js} +26 -25
- package/chunks/{ca-4CQ6MYNQ.js → ca-SLZJD6QH.js} +8 -0
- package/chunks/{channel-management-service-GWY2GAIC.js → channel-management-service-X6LCQUAD.js} +1 -1
- package/chunks/{channel-settings-store-WNWYFHG7.js → channel-settings-store-ZDFXY7VY.js} +30 -29
- package/chunks/{channel-worker-group-7LXCMZ77.js → channel-worker-group-TJ35JDPE.js} +2 -2
- package/chunks/{channel-worker-manager-RYEME4ZZ.js → channel-worker-manager-G5LKWGOG.js} +2 -2
- package/chunks/{chunk-4PKCUT7F.js → chunk-2A6VQJYK.js} +6 -6
- package/chunks/chunk-2C6HJMG3.js +757 -0
- package/chunks/chunk-3PWCMXIR.js +9169 -0
- package/chunks/{chunk-BVJS5BSP.js → chunk-3PWNVF6N.js} +1 -1
- package/chunks/{chunk-X26JYGTD.js → chunk-3SL2P3WX.js} +1 -1
- package/chunks/{chunk-ZYBBISBY.js → chunk-3YRVPHT3.js} +15 -12
- package/chunks/{chunk-AS5IN4GK.js → chunk-47L5MLB5.js} +3 -3
- package/chunks/{chunk-3U3VAL47.js → chunk-4SR45OM4.js} +1 -1
- package/chunks/{chunk-OMLJNPBE.js → chunk-4ZMS3JCR.js} +1 -0
- package/chunks/{chunk-UKMR3CKV.js → chunk-4ZS3BLER.js} +3 -3
- package/chunks/{chunk-5EYKMUUY.js → chunk-544KT7X4.js} +1 -1
- package/chunks/{chunk-TUGSVUJB.js → chunk-55VKMB7X.js} +5 -5
- package/chunks/{chunk-GO7STP6N.js → chunk-5IJSFWQO.js} +4 -4
- package/chunks/{chunk-A4QRWUDE.js → chunk-5IYS4WWR.js} +1 -1
- package/chunks/{chunk-TS6625XH.js → chunk-5MK45KZ3.js} +9 -5
- package/chunks/{chunk-MLPXSYXR.js → chunk-6BJSYAML.js} +25 -16
- package/chunks/{chunk-V57QC6WW.js → chunk-6LAPGPVA.js} +5 -3
- package/chunks/{chunk-NNHNLJ2X.js → chunk-6RDZLBSJ.js} +240 -42
- package/chunks/{chunk-ZZO74WKW.js → chunk-73JUK3ZW.js} +24 -18
- package/chunks/{chunk-N5YPT6PH.js → chunk-7VNHO4MN.js} +7 -4
- package/chunks/{chunk-OVZPVYZB.js → chunk-AKBOLMUF.js} +95 -17
- package/chunks/{chunk-NHDR76JX.js → chunk-BQWNIPTE.js} +1 -1
- package/chunks/{chunk-IWPYVAO2.js → chunk-C3T6M24E.js} +2 -2
- package/chunks/{chunk-NM5V5OVW.js → chunk-CEXU72GE.js} +2 -2
- package/chunks/{chunk-AA2BEKV3.js → chunk-CH5OFRV7.js} +1 -1
- package/chunks/{chunk-MS7GNABG.js → chunk-CXJHQVEK.js} +8 -0
- package/chunks/{chunk-E23IPNGS.js → chunk-CZK622ZK.js} +12 -3
- package/chunks/{chunk-K5IDV3PC.js → chunk-D34RDOLP.js} +12 -2
- package/chunks/{chunk-OXCMMLED.js → chunk-DGJ7O55J.js} +1 -1
- package/chunks/{chunk-DGK6P3BQ.js → chunk-DHUPMYMC.js} +10 -10
- package/chunks/{chunk-O4D7SPJN.js → chunk-DRAONPUW.js} +3 -3
- package/chunks/{chunk-P7MPQI75.js → chunk-DVR7XKO5.js} +1 -1
- package/chunks/{chunk-PP4FUZNV.js → chunk-E5WQMF3K.js} +2 -2
- package/chunks/{chunk-4NFY2S7N.js → chunk-E7REAOTN.js} +15 -0
- package/chunks/{chunk-ZYYTZUI2.js → chunk-EOPBFLA5.js} +3 -3
- package/chunks/{chunk-OOQUVWIG.js → chunk-FN6M5WUL.js} +4 -4
- package/chunks/{chunk-DGZEMW5R.js → chunk-FS5NGKWC.js} +1 -1
- package/chunks/{chunk-MRMJCLIY.js → chunk-G6KI5UOJ.js} +2 -2
- package/chunks/{chunk-6ORZ2EDC.js → chunk-H3SHU2XU.js} +1 -1
- package/chunks/{chunk-GMIEIY3Y.js → chunk-I3N2Z25H.js} +1 -1
- package/chunks/{chunk-BHILXOC3.js → chunk-J63PKMYA.js} +1 -1
- package/chunks/{chunk-KD5BOPLP.js → chunk-J6YS7Z25.js} +98 -4
- package/chunks/chunk-K2Y45XXS.js +3887 -0
- package/chunks/{chunk-RVOJ2FBP.js → chunk-KC4WMLZO.js} +1486 -10574
- package/chunks/{chunk-LJQAUZMR.js → chunk-L3T4V5GZ.js} +925 -92
- package/chunks/{chunk-M6NDLY2T.js → chunk-LD5VIJ7S.js} +1 -1
- package/chunks/{chunk-RIAABG2K.js → chunk-LSO6EL4Y.js} +1 -1
- package/chunks/{chunk-XHRY7BXD.js → chunk-MDIGJH5X.js} +3 -3
- package/chunks/{chunk-MC4TLKEI.js → chunk-MVHJZ3FZ.js} +2 -2
- package/chunks/{chunk-YEYY7TEP.js → chunk-N6RSOOWJ.js} +5 -5
- package/chunks/{chunk-OD2WU5QY.js → chunk-NRPXRNN4.js} +1 -1
- package/chunks/{chunk-CKSJECTU.js → chunk-NVRMCWTP.js} +8 -4
- package/chunks/{chunk-Y3YCSWG5.js → chunk-OBJYN4MX.js} +1 -1
- package/chunks/{chunk-GGDBMYGZ.js → chunk-OEYAK5O6.js} +3 -3
- package/chunks/{chunk-6YKYPVDV.js → chunk-OEZCXK7Y.js} +3 -3
- package/chunks/{chunk-4S5337WV.js → chunk-OFTPCOGR.js} +4312 -2704
- package/chunks/{chunk-7UXUJ5T3.js → chunk-OJB5FYVK.js} +1 -1
- package/chunks/{chunk-WFSTRPRO.js → chunk-OJOP26ET.js} +1 -1
- package/chunks/{chunk-TIGA2IVL.js → chunk-OO4FKHLO.js} +2 -2
- package/chunks/{chunk-BZ263IKX.js → chunk-OVY67CYC.js} +1 -1
- package/chunks/{chunk-PQ36L4F5.js → chunk-P3AA6S7O.js} +1 -1
- package/chunks/{chunk-CU6GJD55.js → chunk-PCETXVVV.js} +1 -1
- package/chunks/{chunk-AFSG32D5.js → chunk-PHN4R2ZV.js} +1 -1
- package/chunks/{chunk-QF2NHSPB.js → chunk-PJSD2FOR.js} +233 -184
- package/chunks/{chunk-NEFOOD54.js → chunk-QAVTWAHL.js} +2 -2
- package/chunks/{chunk-AW4TRXOC.js → chunk-QEHH23OM.js} +1 -1
- package/chunks/{chunk-CZBYX5MY.js → chunk-QEJZUXSK.js} +1 -1
- package/chunks/{chunk-XIT3GURH.js → chunk-QRVHGEVY.js} +3 -3
- package/chunks/{chunk-M732YJPW.js → chunk-RXHBTKMG.js} +2 -2
- package/chunks/{chunk-JOOFMXGF.js → chunk-S7N3HUIB.js} +5 -5
- package/chunks/{chunk-76J3IJ3M.js → chunk-SCZU65AI.js} +3 -3
- package/chunks/{chunk-QIH2HAEN.js → chunk-SFJMFZT5.js} +1 -1
- package/chunks/{chunk-JNDY2MDR.js → chunk-SFTKAX4O.js} +1 -1
- package/chunks/{chunk-WSH6GRKG.js → chunk-SLILKYV2.js} +2 -2
- package/chunks/{chunk-DXIBNLBZ.js → chunk-SNQZZ765.js} +1 -1
- package/chunks/{chunk-V26NVGAU.js → chunk-TSMPNGBC.js} +8 -3
- package/chunks/{chunk-QV5YN5YD.js → chunk-U657UZJN.js} +5 -5
- package/chunks/{chunk-QNQAPSN2.js → chunk-UC67T4SF.js} +3 -1
- package/chunks/{chunk-O565M6A4.js → chunk-UYDGFWIJ.js} +199 -14
- package/chunks/{chunk-OY5RNSV4.js → chunk-V6WEMZPD.js} +3 -3
- package/chunks/{chunk-A267JX7H.js → chunk-VFP5YOHJ.js} +6 -6
- package/chunks/{chunk-HUTNYWBG.js → chunk-VTOLYFWM.js} +18 -10
- package/chunks/{chunk-EZ5RP345.js → chunk-W7EYJGN7.js} +40 -9
- package/chunks/{chunk-BKPPWD33.js → chunk-WAO53ZQF.js} +1 -1
- package/chunks/{chunk-S5DWMTHO.js → chunk-WP4WIUOJ.js} +2 -0
- package/chunks/{chunk-25EYDK42.js → chunk-WPVUOVYX.js} +1 -1
- package/chunks/{chunk-AXN7UPYQ.js → chunk-WSSH2BNO.js} +1 -1
- package/chunks/chunk-WZAD4ZNJ.js +59 -0
- package/chunks/{chunk-JUEPY766.js → chunk-XITLNXLX.js} +2 -2
- package/chunks/{chunk-EL5SXY3T.js → chunk-XT4RKHVE.js} +2 -2
- package/chunks/{chunk-IGGGG5CX.js → chunk-XYRBK56E.js} +4635 -1655
- package/chunks/{chunk-UZPM4XHR.js → chunk-Y4RVDOXV.js} +29 -8
- package/chunks/{chunk-QRCNA3SR.js → chunk-Y7QY6DKW.js} +49 -69
- package/chunks/{chunk-FDGGZIYW.js → chunk-YECDICIO.js} +2 -2
- package/chunks/{chunk-46UV252V.js → chunk-YHC2EYYG.js} +35 -38
- package/chunks/{chunk-U3VNBPUO.js → chunk-YHXQK4SR.js} +2 -2
- package/chunks/{chunk-A4MFR4C5.js → chunk-ZIGC3MUS.js} +2 -4
- package/chunks/{computer-use-77C5FHMW.js → computer-use-YORZJQE5.js} +22 -21
- package/chunks/{config-utils-IVHRSXWI.js → config-utils-NJQA5YLJ.js} +2 -2
- package/chunks/{contextCommand-PJ77GBWL.js → contextCommand-PACHGIF4.js} +24 -23
- package/chunks/{core-runtime-7VMIKUTG.js → core-runtime-6HD5DSPX.js} +22 -21
- package/chunks/{create-sub-session-2L5MQRN4.js → create-sub-session-IQFIPUQA.js} +26 -24
- package/chunks/{cron-create-H7UEPDSN.js → cron-create-NFRZEOQX.js} +2 -2
- package/chunks/{cron-delete-6SZK7YFM.js → cron-delete-GFVSVO7C.js} +2 -2
- package/chunks/{cron-list-H25JIHEZ.js → cron-list-NRW34CLU.js} +2 -2
- package/chunks/{daemon-2KTG7ZBN.js → daemon-XH76IXOC.js} +356 -21
- package/chunks/{daemon-git-worktree-guard-DXYIMWFT.js → daemon-git-worktree-guard-6P27GKSU.js} +24 -23
- package/chunks/{daemon-status-provider-ZDOYJCU6.js → daemon-status-provider-SXS66ZIR.js} +31 -30
- package/chunks/{daemon-trust-policy-E67OYUK2.js → daemon-trust-policy-5QJHAS3N.js} +29 -28
- package/chunks/{daemon-trust-policy-monitor-RYYGCQ3J.js → daemon-trust-policy-monitor-JA2WZRZ3.js} +29 -28
- package/chunks/{de-UBEBKG6V.js → de-AH4LGCF5.js} +8 -0
- package/chunks/{deferred-core-runtime-3SGXFXEQ.js → deferred-core-runtime-R2VWOVG3.js} +22 -21
- package/chunks/{discovery-ORA5J7YP.js → discovery-X2NV535U.js} +1 -1
- package/chunks/{dist-WJ4BHIEW.js → dist-ESS34DHC.js} +72 -0
- package/chunks/{earlyInputCapture-KJMLFVQV.js → earlyInputCapture-PQEEOFKJ.js} +22 -21
- package/chunks/{edit-I4LQFAEC.js → edit-RASZHTU2.js} +25 -23
- package/chunks/{en-X6YV7GME.js → en-MD3GP5YL.js} +8 -0
- package/chunks/{enter-worktree-YNPOJSRH.js → enter-worktree-CH5OMHJE.js} +22 -21
- package/chunks/{enterPlanMode-XCPK62ER.js → enterPlanMode-AQKR3CAH.js} +22 -21
- package/chunks/{environment-S7CTIHMX.js → environment-7QRYIEBA.js} +25 -24
- package/chunks/{errors-7HB2AIDS.js → errors-P2LL5452.js} +24 -23
- package/chunks/{exit-worktree-AIIY7SR6.js → exit-worktree-WUDL26CY.js} +22 -21
- package/chunks/{exitPlanMode-R4JY7V2O.js → exitPlanMode-JM75SAUI.js} +22 -21
- package/chunks/{fast-path-NDJV3ZFJ.js → fast-path-KVNSOHVA.js} +3 -3
- package/chunks/{fast-path-settings-LNOFM2YP.js → fast-path-settings-WHX3J3ZI.js} +2 -2
- package/chunks/{fr-VENTC2BS.js → fr-ZEML2JWS.js} +8 -0
- package/chunks/{gemini-RSUFP5OE.js → gemini-ADMD2EOS.js} +62 -61
- package/chunks/{geminiContentGenerator-SQ5XBPZ7.js → geminiContentGenerator-CS3M7SOS.js} +3 -3
- package/chunks/{glob-J4RUJAHX.js → glob-WIJOGYVV.js} +22 -21
- package/chunks/{goal-tools-VHTNVOKK.js → goal-tools-K5OHOJ6B.js} +1 -1
- package/chunks/{grep-VJWPLFOT.js → grep-CIFRQBR7.js} +22 -21
- package/chunks/{handleAutoUpdate-POCX2MNB.js → handleAutoUpdate-KJ4SN7DM.js} +26 -25
- package/chunks/{i18n-RM5YOICI.js → i18n-36SZUO4C.js} +23 -22
- package/chunks/{image-gen-EXECB5XM.js → image-gen-R4B5VUYB.js} +2 -2
- package/chunks/{initializer-Z2AFGBNR.js → initializer-CW5YCAOL.js} +29 -28
- package/chunks/{installationInfo-4I5FXNMH.js → installationInfo-NMQIOUGY.js} +23 -22
- package/chunks/{ja-QHT4EQTO.js → ja-UM5B2HMD.js} +8 -0
- package/chunks/{list-ZMBFIGZA.js → list-HHGT3S4P.js} +32 -31
- package/chunks/{loadedSettingsAdapter-T6TV4YJ7.js → loadedSettingsAdapter-SJ2MJF35.js} +29 -28
- package/chunks/{loggingContentGenerator-WF4ZOJEZ.js → loggingContentGenerator-GR2QQ2C5.js} +12 -10
- package/chunks/{loop-wakeup-WQS6JYAG.js → loop-wakeup-HWVUU5CF.js} +3 -3
- package/chunks/{managed-npm-update-E7IW6N7V.js → managed-npm-update-ADQJHKTO.js} +23 -22
- package/chunks/{mcp-6UNYX4HG.js → mcp-QW3OTL5W.js} +29 -28
- package/chunks/{monitor-EE2UYMGE.js → monitor-RJKPVERH.js} +22 -21
- package/chunks/{nonInteractiveCli-WAY237O4.js → nonInteractiveCli-MROMHSTL.js} +59 -57
- package/chunks/{notebook-edit-NTDY4QDU.js → notebook-edit-2ENWDBZO.js} +26 -24
- package/chunks/{openaiContentGenerator-YNFVJMRJ.js → openaiContentGenerator-Z3GPWJU4.js} +12 -11
- package/chunks/{pidfile-4XSFLYBZ.js → pidfile-5G42YSTP.js} +22 -21
- package/chunks/{processUtils-WDA2MJFD.js → processUtils-ZDMXYKQY.js} +2 -2
- package/chunks/{pt-VL3I5RNY.js → pt-5BMJ3XYH.js} +8 -0
- package/chunks/{qwenContentGenerator-434M7QKY.js → qwenContentGenerator-NLEMBZVU.js} +25 -24
- package/chunks/{qwenOAuth2-GMYZOO6A.js → qwenOAuth2-EBV52DWJ.js} +3 -3
- package/chunks/{read-file-TAFBKMNI.js → read-file-5BYIF53O.js} +9 -7
- package/chunks/{record-artifact-SEYFJEJF.js → record-artifact-GLU3UWBV.js} +3 -1
- package/chunks/{resumeHistoryUtils-EVG3WYK2.js → resumeHistoryUtils-AFTBRS3G.js} +25 -24
- package/chunks/{ripGrep-WOEK2PXS.js → ripGrep-NN7AOLQY.js} +22 -21
- package/chunks/{ru-4RCKL4PY.js → ru-6GL66ORV.js} +8 -0
- package/chunks/{run-qwen-serve-3QSGRXAN.js → run-qwen-serve-UR3DYDAF.js} +49 -40
- package/chunks/{runtime-5MLLZ7DC.js → runtime-PR5RKGNH.js} +32 -31
- package/chunks/{scheduler-RPBJ63CH.js → scheduler-GPMLVKJM.js} +24 -23
- package/chunks/{sdk-exporters-http-XUVP63H6.js → sdk-exporters-http-NC746HLT.js} +2 -2
- package/chunks/{sdk-impl-YXUEN2Z2.js → sdk-impl-YVL7BP6Y.js} +2 -2
- package/chunks/{send-message-VZENRWRH.js → send-message-TNBG5EVA.js} +1 -1
- package/chunks/{serve-HS3XLPXU.js → serve-E7V2JVA2.js} +29 -30
- package/chunks/{server-TC4A7AAZ.js → server-YXB3DBN7.js} +1267 -165
- package/chunks/{session-UBOFXVMN.js → session-DZEAUT7S.js} +60 -58
- package/chunks/{settings-D5644OM5.js → settings-ESZ3NWAP.js} +28 -27
- package/chunks/{shell-3PZULQQV.js → shell-JMSK5WIL.js} +22 -21
- package/chunks/{skill-PEVVXQ3L.js → skill-5K5CSUJV.js} +11 -9
- package/chunks/{skill-settings-J65JKKES.js → skill-settings-V64NIOTI.js} +28 -27
- package/chunks/{spawnChannel-IYGXRHSQ.js → spawnChannel-S63APBZZ.js} +24 -23
- package/chunks/{standalone-update-IFM53PE7.js → standalone-update-P42HDFXX.js} +24 -23
- package/chunks/{startInteractiveUI-3AVH7L6H.js → startInteractiveUI-LFBLFHJ4.js} +262 -191
- package/chunks/{task-create-FCBDX7UH.js → task-create-EILHJJB7.js} +4 -4
- package/chunks/{task-list-YIYIUFUA.js → task-list-WGJR6YL5.js} +18 -4
- package/chunks/{task-update-MYPFVOVM.js → task-update-XZAHVXJ5.js} +79 -8
- package/chunks/{team-create-ZAIA7KAV.js → team-create-EDNOUM2U.js} +23 -23
- package/chunks/{team-delete-6UMU4XLS.js → team-delete-UEP4QOOT.js} +3 -3
- package/chunks/{team-plan-approval-UNIUS7OD.js → team-plan-approval-QRSNK2DX.js} +22 -21
- package/chunks/{terminal-image-renderer-G343P2RV.js → terminal-image-renderer-6J2NPL32.js} +22 -21
- package/chunks/{theme-manager-Z3RIT7DB.js → theme-manager-WJMLRBXS.js} +22 -21
- package/chunks/{todoWrite-U2R4NVF4.js → todoWrite-ATS62CAP.js} +1 -1
- package/chunks/{tool-search-5R2OE4C7.js → tool-search-MZ6WU7DM.js} +9 -7
- package/chunks/{total-session-admission-4KBHMQQ2.js → total-session-admission-DQVW2LIP.js} +26 -25
- package/chunks/{trustedFolders-LK6T4XC7.js → trustedFolders-QMH25GOX.js} +23 -22
- package/chunks/{update-relaunch-UBKROIC6.js → update-relaunch-EG75LLW5.js} +5 -5
- package/chunks/{updateCheck-W4Y2GFSD.js → updateCheck-MTZIVGT5.js} +25 -24
- package/chunks/{useAutoAcceptIndicator-C7BEICBF.js → useAutoAcceptIndicator-IGCW5EPO.js} +31 -30
- package/chunks/{validateNonInterActiveAuth-LTEI2TB6.js → validateNonInterActiveAuth-D5FPAB2C.js} +56 -54
- package/chunks/{version-G5A5DGVS.js → version-UOLDLLRB.js} +1 -1
- package/chunks/{web-fetch-RTEQTR5Z.js → web-fetch-QKKW6CWH.js} +11 -8
- package/chunks/{web-search-5OXHEZPV.js → web-search-JYRBZMCW.js} +2 -2
- package/chunks/{workflow-ISQJHPG2.js → workflow-SR7SEAU7.js} +139 -37
- package/chunks/{workspace-providers-status-2ZPZPUPZ.js → workspace-providers-status-OXGV4EFF.js} +32 -31
- package/chunks/{workspace-registration-store-CYNY6IP6.js → workspace-registration-store-V5EGKLBH.js} +1 -1
- package/chunks/{workspace-registry-34GTUUHB.js → workspace-registry-KJVIYTF5.js} +26 -25
- package/chunks/{workspace-service-XCDQLE2Y.js → workspace-service-6RLSGUB5.js} +33 -32
- package/chunks/{workspace-skills-status-RS4O7AIJ.js → workspace-skills-status-BHFEPDGH.js} +30 -29
- package/chunks/{workspace-trust-reconciler-AYGXC7A3.js → workspace-trust-reconciler-DB5ERSUN.js} +33 -32
- package/chunks/{write-file-EWXKVVXF.js → write-file-IUP4GTZ4.js} +22 -21
- package/chunks/{zh-TW-SQ4HTSCW.js → zh-TW-LVLBK4KF.js} +8 -0
- package/chunks/{zh-LMSTK4WD.js → zh-UBMWS2BJ.js} +8 -0
- package/chunks/{zoom-image-4BFYJ3HG.js → zoom-image-SRBDTIVA.js} +14 -11
- package/cli.js +13 -13
- package/locales/ca.js +13 -0
- package/locales/de.js +12 -0
- package/locales/en.js +11 -0
- package/locales/fr.js +13 -0
- package/locales/ja.js +13 -0
- package/locales/pt.js +12 -0
- package/locales/ru.js +12 -0
- package/locales/zh-TW.js +11 -0
- package/locales/zh.js +11 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-CgOpDKvm.js → arc-DItbX0DI.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-0Ag_m34F.js → architectureDiagram-3BPJPVTR-CmnIlH8y.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-IwTwFau0.js → blockDiagram-GPEHLZMM-pObnB9kw.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-DLa5GUv8.js → c4Diagram-AAUBKEIU-BNBmMS0Y.js} +1 -1
- package/web-shell/assets/channel-hZnMfWA9.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-DcYP-WFG.js → chunk-2J33WTMH-Dz4JBOO6.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-C8MVPMiQ.js → chunk-4BX2VUAB-Cz2GnvAR.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-BUi4Yfv3.js → chunk-55IACEB6-CC6kOQYx.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-Cy3Su2YY.js → chunk-727SXJPM-Z4lY4gbh.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-Dp8Teqv6.js → chunk-AQP2D5EJ-Yz0hZr3D.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-BDTDM-4j.js → chunk-FMBD7UC4-nKmTWTv9.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-7HfDt0r2.js → chunk-ND2GUHAM-CjZz0f6Y.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-BIBU0uCF.js → chunk-QZHKN3VN-Bab3FpuS.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BRnxm8DX.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BRnxm8DX.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-DRLdcg9p.js → cose-bilkent-S5V4N54A-BuSAGFox.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-DCCgDwqW.js → dagre-BM42HDAG-CRZXTg3g.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CsBTBmk3.js → diagram-2AECGRRQ-BFx1Ayrz.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-C9qjH8Lt.js → diagram-5GNKFQAL-B2hMZ3gS.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-Brjs_lj2.js → diagram-KO2AKTUF-DKxAQLmc.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DtiWCl_F.js → diagram-LMA3HP47-Bo1xGqVY.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-DmfKLkBT.js → diagram-OG6HWLK6-B9NG78d-.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-Bve_4deH.js → erDiagram-TEJ5UH35-DltQKiqQ.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-C2_kXCcV.js → flowDiagram-I6XJVG4X-5xXGmS4I.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-BSBIjiTF.js → ganttDiagram-6RSMTGT7-bhGL5n0l.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CyebwI55.js → gitGraphDiagram-PVQCEYII-ZYnz9hgh.js} +1 -1
- package/web-shell/assets/{index-d0yfnV1M.js → index-CBBeUArD.js} +1 -1
- package/web-shell/assets/index-CbgU-jUo.css +5 -0
- package/web-shell/assets/index-_nhzXqab.js +1750 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-CSDGnWxU.js → infoDiagram-5YYISTIA-Cg-jamQf.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BK4jU13p.js → ishikawaDiagram-YF4QCWOH-CcmvKlyq.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-D_W6j-oF.js → journeyDiagram-JHISSGLW-BRsOQZp1.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-C7xf-SdC.js → kanban-definition-UN3LZRKU-xW-dmEHK.js} +1 -1
- package/web-shell/assets/{linear-DQmzxpxd.js → linear-ClBfEZH2.js} +1 -1
- package/web-shell/assets/{mermaid.core-9P7AGOLG.js → mermaid.core-D65NDkzc.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-DgcgMyPk.js → mindmap-definition-RKZ34NQL-CyvFslYa.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-3wWGb9eG.js → pieDiagram-4H26LBE5-BwSefMyG.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BeCXnQw9.js → quadrantDiagram-W4KKPZXB-GqBJspFS.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-Bi1UOHDz.js → requirementDiagram-4Y6WPE33-B137PlTJ.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-lrLUjjbb.js → sankeyDiagram-5OEKKPKP-maHkkt8i.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-BFuqKz6Q.js → sequenceDiagram-3UESZ5HK-DJ1mRaG3.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-8DemQLhu.js → stateDiagram-AJRCARHV-aRmP7Q4i.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Db39gvZ_.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-uzEuVQXg.js → timeline-definition-PNZ67QCA-CIQ3BRPA.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-BQTeZ_-o.js → vennDiagram-CIIHVFJN-DR9VPd5h.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-B6yM5Im7.js → wardley-L42UT6IY-ZcfIbT4D.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-ChM8bmgn.js → wardleyDiagram-YWT4CUSO-D0jgPi4T.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-oNG6HyB1.js → xychartDiagram-2RQKCTM6-BGWU4s5o.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-MPHPFVKK.js +0 -48
- package/chunks/chunk-RLKC46YT.js +0 -3582
- package/chunks/chunk-UPDOZBWO.js +0 -358
- package/web-shell/assets/channel-BrGVBa2L.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-B5TUzJzI.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B5TUzJzI.js +0 -1
- package/web-shell/assets/index-CIDsgxTe.js +0 -1792
- package/web-shell/assets/index-DiQnWi_E.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DhM5ixYd.js +0 -1
- /package/chunks/{chunk-NTTBXH7U.js → chunk-UGK4K2N2.js} +0 -0
|
@@ -20,13 +20,13 @@ import {
|
|
|
20
20
|
shouldSuppressRememberErrorDetails,
|
|
21
21
|
workspaceMemoryFailureCode,
|
|
22
22
|
workspaceMemoryFailureDiagnostics
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-73JUK3ZW.js";
|
|
24
24
|
import {
|
|
25
25
|
deriveWebSocketBase,
|
|
26
26
|
openQwenAsrRealtimeStream,
|
|
27
27
|
openVoiceStream,
|
|
28
28
|
openVoiceStreamWithRetry
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-WSSH2BNO.js";
|
|
30
30
|
import {
|
|
31
31
|
SetupGithubError,
|
|
32
32
|
collectSessionData,
|
|
@@ -38,15 +38,15 @@ import {
|
|
|
38
38
|
toJson,
|
|
39
39
|
toJsonl,
|
|
40
40
|
toMarkdown
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-K2Y45XXS.js";
|
|
42
42
|
import {
|
|
43
43
|
OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
|
|
44
44
|
ObservedChannelContactStore
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-OVY67CYC.js";
|
|
46
46
|
import {
|
|
47
47
|
escapeAnsiCtrlCodes
|
|
48
|
-
} from "./chunk-
|
|
49
|
-
import "./chunk-
|
|
48
|
+
} from "./chunk-E7REAOTN.js";
|
|
49
|
+
import "./chunk-4SR45OM4.js";
|
|
50
50
|
import "./chunk-2MIN6GRR.js";
|
|
51
51
|
import "./chunk-QHTIBUWB.js";
|
|
52
52
|
import "./chunk-3Z43GZUQ.js";
|
|
@@ -62,11 +62,13 @@ import {
|
|
|
62
62
|
CLIENT_ID_RE,
|
|
63
63
|
ClientMcpSenderRegistry,
|
|
64
64
|
ConversationRuntimeOwnershipError,
|
|
65
|
+
CredentialStore,
|
|
65
66
|
DeviceFlowRegistry,
|
|
66
67
|
MAX_CLIENT_ID_LENGTH,
|
|
67
68
|
MAX_CONCURRENT_VOICE_SESSIONS,
|
|
68
69
|
MAX_SERVER_NAME_LENGTH,
|
|
69
70
|
MAX_TOOL_NAME_LENGTH,
|
|
71
|
+
MutableOriginAllowlist,
|
|
70
72
|
PathMutexRegistry,
|
|
71
73
|
QWEN_CDP_MCP_COMMAND_ENV,
|
|
72
74
|
TooManyActiveDeviceFlowsError,
|
|
@@ -88,7 +90,6 @@ import {
|
|
|
88
90
|
createManagedScratchDirectory,
|
|
89
91
|
createMutationGate,
|
|
90
92
|
createRateLimiter,
|
|
91
|
-
denyBrowserOriginCors,
|
|
92
93
|
detectFromLoopback,
|
|
93
94
|
getAdvertisedServeFeatures,
|
|
94
95
|
getDeferredRuntimeRequestTiming,
|
|
@@ -99,6 +100,8 @@ import {
|
|
|
99
100
|
isBrowserAutomationMcpAvailable,
|
|
100
101
|
isDeepHealthQuery,
|
|
101
102
|
isScratchRootCompatible,
|
|
103
|
+
listenerIdentityOf,
|
|
104
|
+
listenerIdentityOfSocket,
|
|
102
105
|
parseAllowOriginPatterns,
|
|
103
106
|
parseAndValidateWorkspaceClientId,
|
|
104
107
|
parseClientIdHeader,
|
|
@@ -107,6 +110,7 @@ import {
|
|
|
107
110
|
parseMaxQueuedQuery,
|
|
108
111
|
parseOptionalWorkspaceCwd,
|
|
109
112
|
parsePermissionVoteBody,
|
|
113
|
+
requestWasAuthenticated,
|
|
110
114
|
requireSessionId,
|
|
111
115
|
resolveAcpHttpEnabled,
|
|
112
116
|
resolveCdpMcpCommand,
|
|
@@ -116,9 +120,11 @@ import {
|
|
|
116
120
|
sendJsonBodyParserError,
|
|
117
121
|
setDeviceFlowRegistry,
|
|
118
122
|
setRateLimiter,
|
|
123
|
+
singleTokenCredentials,
|
|
124
|
+
tagListener,
|
|
119
125
|
unsafeRevealSecret,
|
|
120
126
|
validateMcpRuntimeServerName
|
|
121
|
-
} from "./chunk-
|
|
127
|
+
} from "./chunk-UYDGFWIJ.js";
|
|
122
128
|
import "./chunk-VGHZT6JR.js";
|
|
123
129
|
import {
|
|
124
130
|
isLoopbackBind,
|
|
@@ -129,7 +135,7 @@ import "./chunk-UXEO7E3V.js";
|
|
|
129
135
|
import {
|
|
130
136
|
evaluateDaemonWorkspaceTrust,
|
|
131
137
|
readDaemonTrustPolicySnapshot
|
|
132
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-QRVHGEVY.js";
|
|
133
139
|
import {
|
|
134
140
|
EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
|
|
135
141
|
MAX_WORKSPACE_SKILL_NAME_LENGTH,
|
|
@@ -143,14 +149,14 @@ import {
|
|
|
143
149
|
validateWorkspaceSkillName,
|
|
144
150
|
validateWorkspaceVoiceState,
|
|
145
151
|
voiceSettingsScopeToWire
|
|
146
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-W7EYJGN7.js";
|
|
147
153
|
import {
|
|
148
154
|
PermissionRulesValidationError,
|
|
149
155
|
buildPermissionSettings,
|
|
150
156
|
isPermissionRuleType,
|
|
151
157
|
normalizePermissionRules,
|
|
152
158
|
readPermissionRuleSet
|
|
153
|
-
} from "./chunk-
|
|
159
|
+
} from "./chunk-OJB5FYVK.js";
|
|
154
160
|
import {
|
|
155
161
|
assertVoiceBaseUrlNetworkAllowed,
|
|
156
162
|
isStreamingVoiceModel,
|
|
@@ -158,12 +164,12 @@ import {
|
|
|
158
164
|
resolveVoiceTranscriptionConfig,
|
|
159
165
|
sanitizeVoiceErrorMessage,
|
|
160
166
|
transcribeVoiceAudio
|
|
161
|
-
} from "./chunk-
|
|
167
|
+
} from "./chunk-H3SHU2XU.js";
|
|
162
168
|
import {
|
|
163
169
|
isVoiceEnabled,
|
|
164
170
|
isVoiceMode,
|
|
165
171
|
readVoiceModel
|
|
166
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-SFJMFZT5.js";
|
|
167
173
|
import "./chunk-WGHHA7ZH.js";
|
|
168
174
|
import {
|
|
169
175
|
createTotalSessionAdmissionController
|
|
@@ -184,18 +190,18 @@ import {
|
|
|
184
190
|
} from "./chunk-4JRM2BSM.js";
|
|
185
191
|
import {
|
|
186
192
|
assertValidChannelSecretUpdates
|
|
187
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-E5WQMF3K.js";
|
|
188
194
|
import {
|
|
189
195
|
createDaemonStatusProvider
|
|
190
|
-
} from "./chunk-
|
|
191
|
-
import "./chunk-
|
|
192
|
-
import "./chunk-
|
|
196
|
+
} from "./chunk-FN6M5WUL.js";
|
|
197
|
+
import "./chunk-UGK4K2N2.js";
|
|
198
|
+
import "./chunk-MDIGJH5X.js";
|
|
193
199
|
import {
|
|
194
200
|
SessionArtifactAuthorizationError,
|
|
195
201
|
SessionArtifactValidationError,
|
|
196
202
|
createAcpSessionBridge,
|
|
197
203
|
parseSessionSource
|
|
198
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-L3T4V5GZ.js";
|
|
199
205
|
import {
|
|
200
206
|
EVENT_SCHEMA_VERSION,
|
|
201
207
|
EventBus,
|
|
@@ -205,17 +211,17 @@ import "./chunk-WCCLLK7X.js";
|
|
|
205
211
|
import "./chunk-OCPBI7J5.js";
|
|
206
212
|
import {
|
|
207
213
|
createWorkspaceProvidersStatusProvider
|
|
208
|
-
} from "./chunk-
|
|
214
|
+
} from "./chunk-N6RSOOWJ.js";
|
|
209
215
|
import {
|
|
210
216
|
getAuthTypeFromEnv,
|
|
211
217
|
resolveCliGenerationConfig
|
|
212
|
-
} from "./chunk-
|
|
218
|
+
} from "./chunk-EOPBFLA5.js";
|
|
213
219
|
import {
|
|
214
220
|
snapshotProcessEnv
|
|
215
|
-
} from "./chunk-
|
|
221
|
+
} from "./chunk-CEXU72GE.js";
|
|
216
222
|
import {
|
|
217
223
|
createWorkspaceSkillsStatusProvider
|
|
218
|
-
} from "./chunk-
|
|
224
|
+
} from "./chunk-V6WEMZPD.js";
|
|
219
225
|
import "./chunk-BGXZBI5B.js";
|
|
220
226
|
import "./chunk-Z4X5MTRT.js";
|
|
221
227
|
import {
|
|
@@ -234,32 +240,32 @@ import {
|
|
|
234
240
|
import {
|
|
235
241
|
daemonObservedContactsPath,
|
|
236
242
|
loadChannelsConfig
|
|
237
|
-
} from "./chunk-
|
|
238
|
-
import "./chunk-
|
|
243
|
+
} from "./chunk-55VKMB7X.js";
|
|
244
|
+
import "./chunk-U657UZJN.js";
|
|
239
245
|
import "./chunk-57OAHC2Y.js";
|
|
240
246
|
import {
|
|
241
247
|
parseChannelWebhookConfigLenient
|
|
242
|
-
} from "./chunk-
|
|
248
|
+
} from "./chunk-NRPXRNN4.js";
|
|
243
249
|
import "./chunk-45NQKMYB.js";
|
|
244
250
|
import {
|
|
245
251
|
supportedChannelCatalog
|
|
246
|
-
} from "./chunk-
|
|
252
|
+
} from "./chunk-5IYS4WWR.js";
|
|
247
253
|
import "./chunk-V6WHFGST.js";
|
|
248
254
|
import {
|
|
249
255
|
getStableLiveDiscoveryBaseDir
|
|
250
|
-
} from "./chunk-
|
|
256
|
+
} from "./chunk-5MK45KZ3.js";
|
|
251
257
|
import {
|
|
252
258
|
LIVE_HOST_BUNDLE_ID,
|
|
253
259
|
LIVE_HOST_PROTOCOL_VERSION,
|
|
254
260
|
LIVE_INPUT_AUDIO_EPOCH_BYTES
|
|
255
261
|
} from "./chunk-NKLP3DCK.js";
|
|
256
|
-
import "./chunk-
|
|
262
|
+
import "./chunk-BQWNIPTE.js";
|
|
257
263
|
import {
|
|
258
264
|
STATUS_SCHEMA_VERSION,
|
|
259
265
|
SessionRestoreTimeoutError,
|
|
260
266
|
createIdleWorkspaceMemoryStatus,
|
|
261
267
|
mapDomainErrorToErrorKind
|
|
262
|
-
} from "./chunk-
|
|
268
|
+
} from "./chunk-UC67T4SF.js";
|
|
263
269
|
import "./chunk-K6KS3LTN.js";
|
|
264
270
|
import "./chunk-FC4KQFCS.js";
|
|
265
271
|
import "./chunk-T3CHYWJZ.js";
|
|
@@ -270,13 +276,13 @@ import {
|
|
|
270
276
|
WorkspaceRegistrationStoreLimitError,
|
|
271
277
|
normalizeWorkspaceDisplayName,
|
|
272
278
|
workspaceRegistrationId
|
|
273
|
-
} from "./chunk-
|
|
279
|
+
} from "./chunk-SFTKAX4O.js";
|
|
274
280
|
import {
|
|
275
281
|
CHANNEL_PROMPT_META_KEY,
|
|
276
282
|
DAEMON_PROMPT_DISPLAY_TEXT_META_KEY,
|
|
277
283
|
REQUESTED_SESSION_ID_META_KEY,
|
|
278
284
|
gradeActiveWorkCoverage
|
|
279
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-WP4WIUOJ.js";
|
|
280
286
|
import {
|
|
281
287
|
BranchWhilePromptActiveError,
|
|
282
288
|
BridgeChannelQuarantinedError,
|
|
@@ -356,26 +362,26 @@ import {
|
|
|
356
362
|
getWritableScopes,
|
|
357
363
|
loadSettings,
|
|
358
364
|
validateSettingValue
|
|
359
|
-
} from "./chunk-
|
|
365
|
+
} from "./chunk-VFP5YOHJ.js";
|
|
360
366
|
import "./chunk-RKUWKYED.js";
|
|
361
|
-
import "./chunk-
|
|
367
|
+
import "./chunk-CZK622ZK.js";
|
|
362
368
|
import "./chunk-GOXKNSDZ.js";
|
|
363
369
|
import "./chunk-IDS7MSUP.js";
|
|
364
370
|
import {
|
|
365
371
|
detectSystemLanguage,
|
|
366
372
|
resolveLanguageSetting
|
|
367
|
-
} from "./chunk-
|
|
373
|
+
} from "./chunk-VTOLYFWM.js";
|
|
368
374
|
import {
|
|
369
375
|
SUPPORTED_LANGUAGES,
|
|
370
376
|
resolveSupportedLanguage
|
|
371
377
|
} from "./chunk-5EJZE3FP.js";
|
|
372
|
-
import "./chunk-
|
|
373
|
-
import "./chunk-
|
|
374
|
-
import "./chunk-
|
|
378
|
+
import "./chunk-MVHJZ3FZ.js";
|
|
379
|
+
import "./chunk-CXJHQVEK.js";
|
|
380
|
+
import "./chunk-PCETXVVV.js";
|
|
375
381
|
import "./chunk-WZMH7II3.js";
|
|
376
382
|
import {
|
|
377
383
|
getWorkspaceTrustStatus
|
|
378
|
-
} from "./chunk-
|
|
384
|
+
} from "./chunk-C3T6M24E.js";
|
|
379
385
|
import "./chunk-NPQ5ZKRP.js";
|
|
380
386
|
import {
|
|
381
387
|
isWithinRoot as isWithinRoot2
|
|
@@ -448,12 +454,13 @@ import {
|
|
|
448
454
|
resolveBranchName,
|
|
449
455
|
resolveProviderProtocol,
|
|
450
456
|
shouldShowStep,
|
|
457
|
+
sleepInhibitor,
|
|
451
458
|
stripTerminalControlSequences,
|
|
452
459
|
watchRepoBranch,
|
|
453
460
|
writeWorkspaceContextFile,
|
|
454
461
|
writeWorktreeSession,
|
|
455
462
|
writeWorktreeSessionMarker
|
|
456
|
-
} from "./chunk-
|
|
463
|
+
} from "./chunk-OFTPCOGR.js";
|
|
457
464
|
import "./chunk-GOFAQQZA.js";
|
|
458
465
|
import "./chunk-5M6IDOMF.js";
|
|
459
466
|
import "./chunk-TWPJO254.js";
|
|
@@ -461,12 +468,12 @@ import "./chunk-CQ35AJ4Z.js";
|
|
|
461
468
|
import {
|
|
462
469
|
MAX_JOBS,
|
|
463
470
|
nextDurableFireMs
|
|
464
|
-
} from "./chunk-
|
|
465
|
-
import "./chunk-
|
|
466
|
-
import "./chunk-
|
|
467
|
-
import "./chunk-
|
|
471
|
+
} from "./chunk-FS5NGKWC.js";
|
|
472
|
+
import "./chunk-SLILKYV2.js";
|
|
473
|
+
import "./chunk-NVRMCWTP.js";
|
|
474
|
+
import "./chunk-AKBOLMUF.js";
|
|
468
475
|
import "./chunk-6PVPNMXU.js";
|
|
469
|
-
import "./chunk-
|
|
476
|
+
import "./chunk-544KT7X4.js";
|
|
470
477
|
import {
|
|
471
478
|
nextFireTime,
|
|
472
479
|
parseCron
|
|
@@ -479,8 +486,8 @@ import {
|
|
|
479
486
|
readCronTasks,
|
|
480
487
|
taskHasLegacyCondition,
|
|
481
488
|
updateCronTasks
|
|
482
|
-
} from "./chunk-
|
|
483
|
-
import "./chunk-
|
|
489
|
+
} from "./chunk-OBJYN4MX.js";
|
|
490
|
+
import "./chunk-2C6HJMG3.js";
|
|
484
491
|
import "./chunk-O6GEWCJA.js";
|
|
485
492
|
import "./chunk-T26EAKDL.js";
|
|
486
493
|
import "./chunk-ZPJWUGCS.js";
|
|
@@ -488,13 +495,13 @@ import "./chunk-CPBF7KYF.js";
|
|
|
488
495
|
import {
|
|
489
496
|
APPROVAL_MODES
|
|
490
497
|
} from "./chunk-RWDNJBWN.js";
|
|
491
|
-
import "./chunk-
|
|
498
|
+
import "./chunk-WPVUOVYX.js";
|
|
492
499
|
import "./chunk-MIPFDQAF.js";
|
|
493
500
|
import "./chunk-MLXTMF7H.js";
|
|
494
501
|
import "./chunk-KV27IEHM.js";
|
|
495
502
|
import "./chunk-E3DYKPYZ.js";
|
|
496
|
-
import "./chunk-
|
|
497
|
-
import "./chunk-
|
|
503
|
+
import "./chunk-4ZMS3JCR.js";
|
|
504
|
+
import "./chunk-DGJ7O55J.js";
|
|
498
505
|
import {
|
|
499
506
|
addDaemonRequestAttribute,
|
|
500
507
|
captureDaemonTelemetryContext,
|
|
@@ -506,7 +513,7 @@ import {
|
|
|
506
513
|
recordDaemonHttpResponse,
|
|
507
514
|
runWithDaemonTelemetryContext,
|
|
508
515
|
withDaemonRequestSpan
|
|
509
|
-
} from "./chunk-
|
|
516
|
+
} from "./chunk-OO4FKHLO.js";
|
|
510
517
|
import "./chunk-SAH4BD2J.js";
|
|
511
518
|
import "./chunk-XLLKYULU.js";
|
|
512
519
|
import "./chunk-PT4I7NBA.js";
|
|
@@ -529,7 +536,7 @@ import {
|
|
|
529
536
|
isDeviceAuthorizationSuccess,
|
|
530
537
|
isDeviceTokenPending,
|
|
531
538
|
isDeviceTokenSuccess
|
|
532
|
-
} from "./chunk-
|
|
539
|
+
} from "./chunk-I3N2Z25H.js";
|
|
533
540
|
import "./chunk-NAVJD2PQ.js";
|
|
534
541
|
import "./chunk-ROIYNTHJ.js";
|
|
535
542
|
import "./chunk-2B2BF7P7.js";
|
|
@@ -537,13 +544,18 @@ import "./chunk-P3QQPMQA.js";
|
|
|
537
544
|
import "./chunk-YZHRN3CF.js";
|
|
538
545
|
import "./chunk-FAAUPSY2.js";
|
|
539
546
|
import "./chunk-KM73TBQ4.js";
|
|
540
|
-
import "./chunk-MPHPFVKK.js";
|
|
541
547
|
import "./chunk-AXMWHKXA.js";
|
|
542
548
|
import "./chunk-GLCZKT5V.js";
|
|
543
549
|
import "./chunk-DJ2GSRLV.js";
|
|
544
550
|
import "./chunk-QFJ5JHQR.js";
|
|
545
551
|
import "./chunk-CR3C7WXL.js";
|
|
546
552
|
import "./chunk-XWRJCPHC.js";
|
|
553
|
+
import {
|
|
554
|
+
parseLineTolerant,
|
|
555
|
+
read
|
|
556
|
+
} from "./chunk-KC4WMLZO.js";
|
|
557
|
+
import "./chunk-YRLW2MSX.js";
|
|
558
|
+
import "./chunk-VGC4I5JJ.js";
|
|
547
559
|
import {
|
|
548
560
|
CursorNotAtLineBoundaryError,
|
|
549
561
|
LargeNonUtf8TextError,
|
|
@@ -551,29 +563,26 @@ import {
|
|
|
551
563
|
decodeBufferWithEncodingInfoAsync,
|
|
552
564
|
getAllGeminiMdFilenames,
|
|
553
565
|
isUtf8CompatibleEncoding,
|
|
554
|
-
isWithinRoot
|
|
555
|
-
|
|
556
|
-
read
|
|
557
|
-
} from "./chunk-RVOJ2FBP.js";
|
|
558
|
-
import "./chunk-YRLW2MSX.js";
|
|
559
|
-
import "./chunk-VGC4I5JJ.js";
|
|
566
|
+
isWithinRoot
|
|
567
|
+
} from "./chunk-3PWCMXIR.js";
|
|
560
568
|
import "./chunk-CHHABXPE.js";
|
|
561
569
|
import "./chunk-MA2HEDVP.js";
|
|
562
570
|
import "./chunk-XUJNK7Y6.js";
|
|
563
571
|
import "./chunk-6HY6IF3Z.js";
|
|
564
|
-
import "./chunk-
|
|
572
|
+
import "./chunk-2A6VQJYK.js";
|
|
565
573
|
import "./chunk-F6WFNA7U.js";
|
|
566
|
-
import "./chunk-
|
|
574
|
+
import "./chunk-WZAD4ZNJ.js";
|
|
567
575
|
import "./chunk-FPGTNKCP.js";
|
|
576
|
+
import "./chunk-YHC2EYYG.js";
|
|
568
577
|
import "./chunk-CPHEPGAO.js";
|
|
569
|
-
import "./chunk-
|
|
570
|
-
import "./chunk-
|
|
578
|
+
import "./chunk-DVR7XKO5.js";
|
|
579
|
+
import "./chunk-YECDICIO.js";
|
|
571
580
|
import {
|
|
572
581
|
redactUrlCredentials,
|
|
573
582
|
stripAnsiAndControl
|
|
574
|
-
} from "./chunk-
|
|
583
|
+
} from "./chunk-XT4RKHVE.js";
|
|
575
584
|
import "./chunk-HHJLM3WQ.js";
|
|
576
|
-
import "./chunk-
|
|
585
|
+
import "./chunk-D34RDOLP.js";
|
|
577
586
|
import {
|
|
578
587
|
FatalConfigError,
|
|
579
588
|
Storage,
|
|
@@ -584,7 +593,8 @@ import {
|
|
|
584
593
|
import "./chunk-VOQXFAY5.js";
|
|
585
594
|
import {
|
|
586
595
|
writeStderrLine,
|
|
587
|
-
writeStderrLineSafe
|
|
596
|
+
writeStderrLineSafe,
|
|
597
|
+
writeStdoutLineSafe
|
|
588
598
|
} from "./chunk-KGJGEEVR.js";
|
|
589
599
|
import "./chunk-75DOP5OR.js";
|
|
590
600
|
import "./chunk-DMTGGOSA.js";
|
|
@@ -607,12 +617,435 @@ import {
|
|
|
607
617
|
|
|
608
618
|
// packages/cli/src/serve/server.ts
|
|
609
619
|
init_esbuild_shims();
|
|
610
|
-
var
|
|
620
|
+
var import_express7 = __toESM(require_express(), 1);
|
|
611
621
|
import * as path18 from "node:path";
|
|
612
622
|
|
|
623
|
+
// packages/cli/src/serve/local-control/index.ts
|
|
624
|
+
init_esbuild_shims();
|
|
625
|
+
|
|
626
|
+
// packages/cli/src/serve/local-control/lan-interfaces.ts
|
|
627
|
+
init_esbuild_shims();
|
|
628
|
+
import { networkInterfaces } from "node:os";
|
|
629
|
+
function isLanIpv4(address) {
|
|
630
|
+
const octets = address.split(".").map((part) => Number(part));
|
|
631
|
+
if (octets.length !== 4 || octets.some((o) => !Number.isInteger(o))) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
const [a, b] = octets;
|
|
635
|
+
if (a === 10) return true;
|
|
636
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
637
|
+
if (a === 192 && b === 168) return true;
|
|
638
|
+
if (a === 169 && b === 254) return true;
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
__name(isLanIpv4, "isLanIpv4");
|
|
642
|
+
function isSoftwareNetwork(interfaceName) {
|
|
643
|
+
if (/vpn/i.test(interfaceName)) return true;
|
|
644
|
+
return /(^|[\s_.-])(utun|tun|tap|ppp|ipsec|wg|wireguard|tailscale|zerotier|zt[a-z0-9]*|hamachi|nordlynx|proton|wintun|docker|veth[0-9a-f]+|vmnet|vboxnet|vethernet|virtualbox|host[- ]only|podman|cni|lxcbr|lxdbr|flannel|virbr|br-[0-9a-f]+|bridge\d|anyconnect|globalprotect|pulse[\s-]secure|forticlient|fortinet|ivanti|cisco[\s_-]secure|citrix|sonicwall|cloudflare)(\d|[\s_.-]|$)/i.test(
|
|
645
|
+
interfaceName
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
__name(isSoftwareNetwork, "isSoftwareNetwork");
|
|
649
|
+
function listLanCandidates(interfaces = networkInterfaces()) {
|
|
650
|
+
const candidates = [];
|
|
651
|
+
for (const [interfaceName, addresses] of Object.entries(interfaces).sort()) {
|
|
652
|
+
if (isSoftwareNetwork(interfaceName)) continue;
|
|
653
|
+
for (const address of addresses ?? []) {
|
|
654
|
+
if (address.family !== "IPv4" || address.internal) continue;
|
|
655
|
+
if (!isLanIpv4(address.address)) continue;
|
|
656
|
+
candidates.push({ interfaceName, address: address.address });
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return candidates;
|
|
660
|
+
}
|
|
661
|
+
__name(listLanCandidates, "listLanCandidates");
|
|
662
|
+
var NoLanInterfaceError = class extends Error {
|
|
663
|
+
static {
|
|
664
|
+
__name(this, "NoLanInterfaceError");
|
|
665
|
+
}
|
|
666
|
+
code = "no_lan_interface";
|
|
667
|
+
constructor() {
|
|
668
|
+
super(
|
|
669
|
+
"No private IPv4 address is available. Local Control needs the host to be on a local network (Wi-Fi or Ethernet)."
|
|
670
|
+
);
|
|
671
|
+
this.name = "NoLanInterfaceError";
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
var AmbiguousLanInterfaceError = class extends Error {
|
|
675
|
+
static {
|
|
676
|
+
__name(this, "AmbiguousLanInterfaceError");
|
|
677
|
+
}
|
|
678
|
+
code = "ambiguous_lan_interface";
|
|
679
|
+
candidates;
|
|
680
|
+
constructor(candidates) {
|
|
681
|
+
super(
|
|
682
|
+
"Multiple local networks are available; choose which one to expose: " + candidates.map((c) => `${c.interfaceName} (${c.address})`).join(", ")
|
|
683
|
+
);
|
|
684
|
+
this.name = "AmbiguousLanInterfaceError";
|
|
685
|
+
this.candidates = candidates;
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
var UnknownLanInterfaceError = class extends Error {
|
|
689
|
+
static {
|
|
690
|
+
__name(this, "UnknownLanInterfaceError");
|
|
691
|
+
}
|
|
692
|
+
code = "unknown_lan_interface";
|
|
693
|
+
constructor(requested) {
|
|
694
|
+
super(
|
|
695
|
+
`${requested} is not a private IPv4 address on this host right now. The network may have changed since the list was fetched.`
|
|
696
|
+
);
|
|
697
|
+
this.name = "UnknownLanInterfaceError";
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
function selectLanAddress(preferredAddress, interfaces = networkInterfaces()) {
|
|
701
|
+
const candidates = listLanCandidates(interfaces);
|
|
702
|
+
if (candidates.length === 0) throw new NoLanInterfaceError();
|
|
703
|
+
if (preferredAddress !== void 0) {
|
|
704
|
+
const match = candidates.find((c) => c.address === preferredAddress);
|
|
705
|
+
if (!match) throw new UnknownLanInterfaceError(preferredAddress);
|
|
706
|
+
return match;
|
|
707
|
+
}
|
|
708
|
+
if (candidates.length > 1) throw new AmbiguousLanInterfaceError(candidates);
|
|
709
|
+
return candidates[0];
|
|
710
|
+
}
|
|
711
|
+
__name(selectLanAddress, "selectLanAddress");
|
|
712
|
+
|
|
713
|
+
// packages/cli/src/serve/local-control/service.ts
|
|
714
|
+
init_esbuild_shims();
|
|
715
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
716
|
+
import { readFileSync } from "node:fs";
|
|
717
|
+
import { createServer } from "node:http";
|
|
718
|
+
import { createServer as createSecureServer } from "node:https";
|
|
719
|
+
var CORS_KEY = "local-control";
|
|
720
|
+
var MAX_CONNECTIONS = 64;
|
|
721
|
+
var HEADERS_TIMEOUT_MS = 1e4;
|
|
722
|
+
var KEEP_ALIVE_TIMEOUT_MS = 5e3;
|
|
723
|
+
var REQUEST_TIMEOUT_MS = 30 * 6e4;
|
|
724
|
+
var InvalidLocalControlTargetError = class extends Error {
|
|
725
|
+
static {
|
|
726
|
+
__name(this, "InvalidLocalControlTargetError");
|
|
727
|
+
}
|
|
728
|
+
code = "invalid_local_control_target";
|
|
729
|
+
constructor() {
|
|
730
|
+
super("Local Control target must be a valid URL target.");
|
|
731
|
+
this.name = "InvalidLocalControlTargetError";
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
var LocalControlService = class {
|
|
735
|
+
static {
|
|
736
|
+
__name(this, "LocalControlService");
|
|
737
|
+
}
|
|
738
|
+
#deps;
|
|
739
|
+
#server;
|
|
740
|
+
#token;
|
|
741
|
+
#selected;
|
|
742
|
+
#sleep;
|
|
743
|
+
#url;
|
|
744
|
+
#transition = Promise.resolve();
|
|
745
|
+
constructor(deps) {
|
|
746
|
+
this.#deps = deps;
|
|
747
|
+
}
|
|
748
|
+
get active() {
|
|
749
|
+
return this.#server !== void 0;
|
|
750
|
+
}
|
|
751
|
+
status() {
|
|
752
|
+
if (!this.#server || !this.#token || !this.#selected) {
|
|
753
|
+
return { active: false };
|
|
754
|
+
}
|
|
755
|
+
return {
|
|
756
|
+
active: true,
|
|
757
|
+
url: this.#url,
|
|
758
|
+
interfaceName: this.#selected.interfaceName,
|
|
759
|
+
address: this.#selected.address,
|
|
760
|
+
port: this.#deps.getPort(),
|
|
761
|
+
sleepInhibited: this.#sleep !== void 0 && sleepInhibitor.isRunning(),
|
|
762
|
+
encrypted: this.#deps.tlsPaths !== void 0
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Bring the LAN listener up. Enabling while already active is a no-op that
|
|
767
|
+
* returns the existing status rather than re-minting: a second scan of the
|
|
768
|
+
* same QR must keep working, and silently invalidating the token the user is
|
|
769
|
+
* mid-pairing with would be indistinguishable from a bug.
|
|
770
|
+
*/
|
|
771
|
+
async enable(options = {}) {
|
|
772
|
+
return this.#serialize(() => this.#enable(options));
|
|
773
|
+
}
|
|
774
|
+
async #enable(options) {
|
|
775
|
+
if (this.active) return this.status();
|
|
776
|
+
const selected = selectLanAddress(options.address);
|
|
777
|
+
const port = this.#deps.getPort();
|
|
778
|
+
const authority = `${selected.address}:${port}`;
|
|
779
|
+
const token = mintPairingToken();
|
|
780
|
+
const tls = this.#deps.tlsPaths;
|
|
781
|
+
const scheme = tls ? "https" : "http";
|
|
782
|
+
const origin = new URL(`${scheme}://${authority}`).origin;
|
|
783
|
+
const url = buildPairedUrl(scheme, authority, token.secret, options.target);
|
|
784
|
+
const server = tls ? createSecureServer(
|
|
785
|
+
{ cert: readFileSync(tls.cert), key: readFileSync(tls.key) },
|
|
786
|
+
this.#deps.app
|
|
787
|
+
) : createServer(this.#deps.app);
|
|
788
|
+
server.maxConnections = MAX_CONNECTIONS;
|
|
789
|
+
server.headersTimeout = HEADERS_TIMEOUT_MS;
|
|
790
|
+
server.requestTimeout = REQUEST_TIMEOUT_MS;
|
|
791
|
+
server.keepAliveTimeout = KEEP_ALIVE_TIMEOUT_MS;
|
|
792
|
+
tagListener(server, { kind: "local-control", authority, origin });
|
|
793
|
+
this.#deps.credentials.addPairingToken(token.id, token.secret);
|
|
794
|
+
this.#deps.originAllowlist.add(CORS_KEY, origin);
|
|
795
|
+
try {
|
|
796
|
+
this.#deps.attachWebSocket(server);
|
|
797
|
+
await listen(server, port, selected.address);
|
|
798
|
+
} catch (error2) {
|
|
799
|
+
this.#deps.detachWebSocket(server);
|
|
800
|
+
this.#deps.credentials.revokePairingToken(token.id);
|
|
801
|
+
this.#deps.originAllowlist.remove(CORS_KEY);
|
|
802
|
+
throw error2;
|
|
803
|
+
}
|
|
804
|
+
server.on("error", (error2) => {
|
|
805
|
+
writeStderrLine(
|
|
806
|
+
`qwen serve: Local Control listener error: ${error2.message}`
|
|
807
|
+
);
|
|
808
|
+
});
|
|
809
|
+
this.#server = server;
|
|
810
|
+
this.#token = token;
|
|
811
|
+
this.#selected = selected;
|
|
812
|
+
this.#url = url;
|
|
813
|
+
this.#sleep = sleepInhibitor.acquire("Qwen Code Local Control is active");
|
|
814
|
+
return this.status();
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Take the LAN listener down and invalidate its credential.
|
|
818
|
+
*
|
|
819
|
+
* Revocation happens first and unconditionally. If closing the socket fails
|
|
820
|
+
* or hangs, the outcome is a listener that accepts connections no credential
|
|
821
|
+
* can authenticate — inert. The reverse order would leave a live, reachable
|
|
822
|
+
* listener with a valid token if teardown failed partway.
|
|
823
|
+
*/
|
|
824
|
+
async disable() {
|
|
825
|
+
return this.#serialize(() => this.#disable());
|
|
826
|
+
}
|
|
827
|
+
async #disable() {
|
|
828
|
+
const server = this.#server;
|
|
829
|
+
const token = this.#token;
|
|
830
|
+
this.#server = void 0;
|
|
831
|
+
this.#token = void 0;
|
|
832
|
+
this.#selected = void 0;
|
|
833
|
+
this.#url = void 0;
|
|
834
|
+
if (token) this.#deps.credentials.revokePairingToken(token.id);
|
|
835
|
+
this.#deps.originAllowlist.remove(CORS_KEY);
|
|
836
|
+
this.#sleep?.release();
|
|
837
|
+
this.#sleep = void 0;
|
|
838
|
+
if (server) {
|
|
839
|
+
this.#deps.detachWebSocket(server);
|
|
840
|
+
await close(server);
|
|
841
|
+
}
|
|
842
|
+
return { active: false };
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Called from the daemon's drain path. Local Control must not outlive the
|
|
846
|
+
* daemon that owns it: a listener surviving drain would hold the port and
|
|
847
|
+
* keep answering with a token nothing can revoke anymore.
|
|
848
|
+
*/
|
|
849
|
+
async dispose() {
|
|
850
|
+
await this.disable();
|
|
851
|
+
}
|
|
852
|
+
async #serialize(operation) {
|
|
853
|
+
const previous = this.#transition;
|
|
854
|
+
let release;
|
|
855
|
+
this.#transition = new Promise((resolve7) => {
|
|
856
|
+
release = resolve7;
|
|
857
|
+
});
|
|
858
|
+
await previous;
|
|
859
|
+
try {
|
|
860
|
+
return await operation();
|
|
861
|
+
} finally {
|
|
862
|
+
release();
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
function mintPairingToken() {
|
|
867
|
+
const secret = randomBytes(32).toString("base64url");
|
|
868
|
+
return { id: randomUUID(), secret };
|
|
869
|
+
}
|
|
870
|
+
__name(mintPairingToken, "mintPairingToken");
|
|
871
|
+
function buildPairedUrl(scheme, authority, secret, target) {
|
|
872
|
+
const url = new URL(`${scheme}://${authority}`);
|
|
873
|
+
if (target) {
|
|
874
|
+
let resolved;
|
|
875
|
+
try {
|
|
876
|
+
resolved = new URL(target, url);
|
|
877
|
+
} catch {
|
|
878
|
+
throw new InvalidLocalControlTargetError();
|
|
879
|
+
}
|
|
880
|
+
url.pathname = resolved.pathname;
|
|
881
|
+
url.search = resolved.search;
|
|
882
|
+
}
|
|
883
|
+
url.hash = `token=${encodeURIComponent(secret)}`;
|
|
884
|
+
return url.toString();
|
|
885
|
+
}
|
|
886
|
+
__name(buildPairedUrl, "buildPairedUrl");
|
|
887
|
+
function listen(server, port, host) {
|
|
888
|
+
return new Promise((resolve7, reject) => {
|
|
889
|
+
const onError = /* @__PURE__ */ __name((error2) => {
|
|
890
|
+
server.removeListener("listening", onListening);
|
|
891
|
+
reject(error2);
|
|
892
|
+
}, "onError");
|
|
893
|
+
const onListening = /* @__PURE__ */ __name(() => {
|
|
894
|
+
server.removeListener("error", onError);
|
|
895
|
+
resolve7();
|
|
896
|
+
}, "onListening");
|
|
897
|
+
server.once("error", onError);
|
|
898
|
+
server.once("listening", onListening);
|
|
899
|
+
server.listen(port, host);
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
__name(listen, "listen");
|
|
903
|
+
function close(server) {
|
|
904
|
+
return new Promise((resolve7) => {
|
|
905
|
+
server.closeAllConnections?.();
|
|
906
|
+
server.close(() => resolve7());
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
__name(close, "close");
|
|
910
|
+
|
|
911
|
+
// packages/cli/src/serve/routes/workspace-local-control.ts
|
|
912
|
+
init_esbuild_shims();
|
|
913
|
+
async function withUiData(status) {
|
|
914
|
+
let qrText;
|
|
915
|
+
if (status.url) {
|
|
916
|
+
try {
|
|
917
|
+
const { default: qrcode } = await import("./main-PXAUXNF2.js");
|
|
918
|
+
qrcode.setErrorLevel("Q");
|
|
919
|
+
qrcode.generate(status.url, { small: true }, (code) => {
|
|
920
|
+
qrText = code.trimEnd();
|
|
921
|
+
});
|
|
922
|
+
} catch {
|
|
923
|
+
qrText = void 0;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return { ...status, qrText, interfaces: listLanCandidates() };
|
|
927
|
+
}
|
|
928
|
+
__name(withUiData, "withUiData");
|
|
929
|
+
function presentStatus(req, ui) {
|
|
930
|
+
if (requestWasAuthenticated(req)) return ui;
|
|
931
|
+
const { url: _url, qrText: _qrText, ...rest } = ui;
|
|
932
|
+
return { ...rest, urlRedacted: ui.url !== void 0 };
|
|
933
|
+
}
|
|
934
|
+
__name(presentStatus, "presentStatus");
|
|
935
|
+
function requirePrimaryListener(req, res) {
|
|
936
|
+
if (listenerIdentityOf(req).kind === "primary") return true;
|
|
937
|
+
res.status(403).json({
|
|
938
|
+
error: "Local Control can only be enabled from the machine running the daemon.",
|
|
939
|
+
code: "local_control_remote_enable_denied"
|
|
940
|
+
});
|
|
941
|
+
return false;
|
|
942
|
+
}
|
|
943
|
+
__name(requirePrimaryListener, "requirePrimaryListener");
|
|
944
|
+
function registerWorkspaceLocalControlRoutes(app, deps) {
|
|
945
|
+
app.get("/workspace/local-control", async (req, res) => {
|
|
946
|
+
res.status(200).json(presentStatus(req, await withUiData(deps.service.status())));
|
|
947
|
+
});
|
|
948
|
+
app.post(
|
|
949
|
+
"/workspace/local-control/enable",
|
|
950
|
+
deps.mutate(),
|
|
951
|
+
async (req, res) => {
|
|
952
|
+
if (!requirePrimaryListener(req, res)) return;
|
|
953
|
+
if (deps.webShellAvailable === false) {
|
|
954
|
+
res.status(409).json({
|
|
955
|
+
error: "Local Control requires the Web Shell.",
|
|
956
|
+
code: "local_control_web_shell_unavailable"
|
|
957
|
+
});
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
if (deps.primaryBindHostname !== void 0 && !isLoopbackBind(deps.primaryBindHostname)) {
|
|
961
|
+
res.status(409).json({
|
|
962
|
+
error: "Local Control requires the daemon to be bound to loopback; restart it with --hostname 127.0.0.1.",
|
|
963
|
+
code: "local_control_non_loopback_bind"
|
|
964
|
+
});
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
if (deps.isDaemonDraining?.()) {
|
|
968
|
+
res.status(503).json({
|
|
969
|
+
error: "Daemon is shutting down.",
|
|
970
|
+
code: "daemon_draining"
|
|
971
|
+
});
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
const body = deps.safeBody(req) ?? {};
|
|
975
|
+
try {
|
|
976
|
+
const ui = await withUiData(
|
|
977
|
+
await deps.service.enable({
|
|
978
|
+
address: typeof body.address === "string" ? body.address : void 0,
|
|
979
|
+
target: typeof body.target === "string" ? body.target : void 0
|
|
980
|
+
})
|
|
981
|
+
);
|
|
982
|
+
if (!requestWasAuthenticated(req) && ui.url) {
|
|
983
|
+
writeStdoutLineSafe(
|
|
984
|
+
`qwen serve: Local Control pairing URL: ${ui.url}`
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
res.status(200).json(presentStatus(req, ui));
|
|
988
|
+
} catch (error2) {
|
|
989
|
+
sendEnableError(res, error2);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
);
|
|
993
|
+
app.post(
|
|
994
|
+
"/workspace/local-control/disable",
|
|
995
|
+
deps.mutate(),
|
|
996
|
+
async (req, res) => {
|
|
997
|
+
if (listenerIdentityOf(req).kind === "local-control") {
|
|
998
|
+
queueMicrotask(() => {
|
|
999
|
+
void deps.service.disable().catch((error2) => {
|
|
1000
|
+
writeStderrLine(
|
|
1001
|
+
`qwen serve: Local Control disable failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
1002
|
+
);
|
|
1003
|
+
});
|
|
1004
|
+
});
|
|
1005
|
+
res.status(200).json({ active: false });
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
res.status(200).json(
|
|
1009
|
+
presentStatus(req, await withUiData(await deps.service.disable()))
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
__name(registerWorkspaceLocalControlRoutes, "registerWorkspaceLocalControlRoutes");
|
|
1015
|
+
function sendEnableError(res, error2) {
|
|
1016
|
+
if (error2 instanceof AmbiguousLanInterfaceError) {
|
|
1017
|
+
res.status(409).json({
|
|
1018
|
+
error: error2.message,
|
|
1019
|
+
code: error2.code,
|
|
1020
|
+
interfaces: error2.candidates
|
|
1021
|
+
});
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
if (error2 instanceof NoLanInterfaceError) {
|
|
1025
|
+
res.status(409).json({ error: error2.message, code: error2.code });
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
if (error2 instanceof UnknownLanInterfaceError) {
|
|
1029
|
+
res.status(409).json({
|
|
1030
|
+
error: error2.message,
|
|
1031
|
+
code: error2.code,
|
|
1032
|
+
interfaces: listLanCandidates()
|
|
1033
|
+
});
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
if (error2 instanceof InvalidLocalControlTargetError) {
|
|
1037
|
+
res.status(400).json({ error: error2.message, code: error2.code });
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
res.status(500).json({
|
|
1041
|
+
error: error2 instanceof Error ? error2.message : String(error2),
|
|
1042
|
+
code: "local_control_enable_failed"
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
__name(sendEnableError, "sendEnableError");
|
|
1046
|
+
|
|
613
1047
|
// packages/cli/src/serve/acp-http/index.ts
|
|
614
1048
|
init_esbuild_shims();
|
|
615
|
-
import { createHash as createHash3, timingSafeEqual } from "node:crypto";
|
|
616
1049
|
|
|
617
1050
|
// packages/cli/src/serve/acp-http/dispatch.ts
|
|
618
1051
|
init_esbuild_shims();
|
|
@@ -1131,6 +1564,7 @@ function createAuditPublisher(deps) {
|
|
|
1131
1564
|
if (record.sizeBytes !== void 0) payload.sizeBytes = record.sizeBytes;
|
|
1132
1565
|
if (record.truncated) payload.truncated = true;
|
|
1133
1566
|
if (record.matchedIgnore) payload.matchedIgnore = record.matchedIgnore;
|
|
1567
|
+
if (record.operation !== void 0) payload.operation = record.operation;
|
|
1134
1568
|
if (record.pattern !== void 0 && includeRawPaths) {
|
|
1135
1569
|
payload.pattern = record.pattern;
|
|
1136
1570
|
}
|
|
@@ -1177,7 +1611,7 @@ __name(createAuditPublisher, "createAuditPublisher");
|
|
|
1177
1611
|
|
|
1178
1612
|
// packages/cli/src/serve/fs/workspace-file-system.ts
|
|
1179
1613
|
init_esbuild_shims();
|
|
1180
|
-
import { createHash as createHash2, randomBytes } from "node:crypto";
|
|
1614
|
+
import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
|
|
1181
1615
|
import { constants as fsConstants, promises as fsp2 } from "node:fs";
|
|
1182
1616
|
import * as path4 from "node:path";
|
|
1183
1617
|
|
|
@@ -1238,6 +1672,11 @@ function assertCursorMatchesFile(cursor, stats, path19) {
|
|
|
1238
1672
|
__name(assertCursorMatchesFile, "assertCursorMatchesFile");
|
|
1239
1673
|
|
|
1240
1674
|
// packages/cli/src/serve/fs/workspace-file-system.ts
|
|
1675
|
+
var OWNER_ONLY_NEW_FILE_MODE = 384;
|
|
1676
|
+
function resolveNewFileModeBits(policy, umask) {
|
|
1677
|
+
return policy === "system" ? 438 & ~(umask ?? process.umask()) : OWNER_ONLY_NEW_FILE_MODE;
|
|
1678
|
+
}
|
|
1679
|
+
__name(resolveNewFileModeBits, "resolveNewFileModeBits");
|
|
1241
1680
|
function createWorkspaceFileSystemFactory(deps) {
|
|
1242
1681
|
const boundWorkspaces = canonicalizeWorkspaces(deps.boundWorkspaces);
|
|
1243
1682
|
if (boundWorkspaces.length === 0) {
|
|
@@ -1263,6 +1702,7 @@ function createWorkspaceFileSystemFactory(deps) {
|
|
|
1263
1702
|
});
|
|
1264
1703
|
const lowFs = new StandardFileSystemService();
|
|
1265
1704
|
const pathLocks = deps.pathLocks ?? new PathMutexRegistry();
|
|
1705
|
+
const newFileMode = deps.newFileMode ?? "owner";
|
|
1266
1706
|
const forRequest = /* @__PURE__ */ __name((ctx) => new WorkspaceFileSystemImpl({
|
|
1267
1707
|
primaryWorkspace,
|
|
1268
1708
|
workspaces,
|
|
@@ -1271,7 +1711,8 @@ function createWorkspaceFileSystemFactory(deps) {
|
|
|
1271
1711
|
ctx,
|
|
1272
1712
|
lowFs,
|
|
1273
1713
|
pathLocks,
|
|
1274
|
-
generationGuard: deps.generationGuard
|
|
1714
|
+
generationGuard: deps.generationGuard,
|
|
1715
|
+
newFileMode
|
|
1275
1716
|
}), "forRequest");
|
|
1276
1717
|
return {
|
|
1277
1718
|
assertCanWrite() {
|
|
@@ -1304,7 +1745,8 @@ function createWorkspaceFileSystemFactory(deps) {
|
|
|
1304
1745
|
audit,
|
|
1305
1746
|
ctx,
|
|
1306
1747
|
pathLocks,
|
|
1307
|
-
generationGuard: deps.generationGuard
|
|
1748
|
+
generationGuard: deps.generationGuard,
|
|
1749
|
+
newFileMode
|
|
1308
1750
|
});
|
|
1309
1751
|
return;
|
|
1310
1752
|
} catch (outsideErr) {
|
|
@@ -1343,6 +1785,7 @@ async function writeSameHostToolTextOutsideWorkspace(deps) {
|
|
|
1343
1785
|
content,
|
|
1344
1786
|
mode: "overwrite",
|
|
1345
1787
|
meta,
|
|
1788
|
+
newFileModeBits: resolveNewFileModeBits(deps.newFileMode),
|
|
1346
1789
|
assertGenerationOpen: /* @__PURE__ */ __name(() => deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1347
1790
|
});
|
|
1348
1791
|
deps.audit.recordAccess(deps.ctx, {
|
|
@@ -1862,6 +2305,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1862
2305
|
mode: opts.mode,
|
|
1863
2306
|
expectedHash: opts.expectedHash,
|
|
1864
2307
|
meta,
|
|
2308
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
1865
2309
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1866
2310
|
});
|
|
1867
2311
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -1924,6 +2368,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1924
2368
|
content,
|
|
1925
2369
|
mode: "overwrite",
|
|
1926
2370
|
meta,
|
|
2371
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
1927
2372
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1928
2373
|
});
|
|
1929
2374
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -2035,6 +2480,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
2035
2480
|
mode: "replace",
|
|
2036
2481
|
expectedHash: opts.expectedHash,
|
|
2037
2482
|
meta,
|
|
2483
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
2038
2484
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
2039
2485
|
});
|
|
2040
2486
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -2098,6 +2544,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
2098
2544
|
content: next,
|
|
2099
2545
|
mode: "overwrite",
|
|
2100
2546
|
meta: mergeWriteMeta(snapshot.meta, {}),
|
|
2547
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
2101
2548
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
2102
2549
|
});
|
|
2103
2550
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -2149,6 +2596,36 @@ var WorkspaceFileSystemImpl = class {
|
|
|
2149
2596
|
});
|
|
2150
2597
|
}
|
|
2151
2598
|
}
|
|
2599
|
+
async mkdir(p, opts) {
|
|
2600
|
+
const start = performance.now();
|
|
2601
|
+
try {
|
|
2602
|
+
this.deps.generationGuard?.assertOpen();
|
|
2603
|
+
assertTrustedForIntent(this.deps.trusted, "write");
|
|
2604
|
+
const out = await this.deps.pathLocks.runExclusive(
|
|
2605
|
+
p,
|
|
2606
|
+
async () => {
|
|
2607
|
+
await ensureResolvedDirectory(p, {
|
|
2608
|
+
recursive: opts?.recursive ?? false,
|
|
2609
|
+
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
2610
|
+
});
|
|
2611
|
+
this.deps.generationGuard?.assertOpen();
|
|
2612
|
+
const verdict = this.ignoreVerdict(p, "directory");
|
|
2613
|
+
this.deps.audit.recordAccess(this.deps.ctx, {
|
|
2614
|
+
intent: "write",
|
|
2615
|
+
absolute: p,
|
|
2616
|
+
durationMs: performance.now() - start,
|
|
2617
|
+
sizeBytes: 0,
|
|
2618
|
+
operation: "mkdir",
|
|
2619
|
+
matchedIgnore: verdict.ignored ? verdict.category : void 0
|
|
2620
|
+
});
|
|
2621
|
+
return void 0;
|
|
2622
|
+
}
|
|
2623
|
+
);
|
|
2624
|
+
return out;
|
|
2625
|
+
} catch (err) {
|
|
2626
|
+
throw this.recordAndWrap(err, "write", p);
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2152
2629
|
/**
|
|
2153
2630
|
* Coerce an arbitrary thrown value into an `FsError`, emit the
|
|
2154
2631
|
* matching `fs.denied` audit event, and return the typed error
|
|
@@ -2632,10 +3109,82 @@ async function atomicWriteTextResolvedFile(input) {
|
|
|
2632
3109
|
buf,
|
|
2633
3110
|
mode: input.mode,
|
|
2634
3111
|
expectedHash: input.expectedHash,
|
|
3112
|
+
newFileModeBits: input.newFileModeBits,
|
|
2635
3113
|
assertGenerationOpen: input.assertGenerationOpen
|
|
2636
3114
|
});
|
|
2637
3115
|
}
|
|
2638
3116
|
__name(atomicWriteTextResolvedFile, "atomicWriteTextResolvedFile");
|
|
3117
|
+
async function ensureResolvedDirectory(target, opts) {
|
|
3118
|
+
const assertRealDirectory = /* @__PURE__ */ __name(async (p) => {
|
|
3119
|
+
const st = await fsp2.lstat(p);
|
|
3120
|
+
if (st.isSymbolicLink()) {
|
|
3121
|
+
throw new FsError("symlink_escape", `directory path is a symlink: ${p}`, {
|
|
3122
|
+
hint: "re-resolve the target after detecting symlink swaps"
|
|
3123
|
+
});
|
|
3124
|
+
}
|
|
3125
|
+
if (!st.isDirectory()) {
|
|
3126
|
+
throw new FsError(
|
|
3127
|
+
"parse_error",
|
|
3128
|
+
`path exists and is not a directory: ${p}`
|
|
3129
|
+
);
|
|
3130
|
+
}
|
|
3131
|
+
}, "assertRealDirectory");
|
|
3132
|
+
const assertParentNotSymlink = /* @__PURE__ */ __name(async (p) => {
|
|
3133
|
+
const parent = path4.dirname(p);
|
|
3134
|
+
const st = await fsp2.lstat(parent);
|
|
3135
|
+
if (st.isSymbolicLink()) {
|
|
3136
|
+
throw new FsError(
|
|
3137
|
+
"symlink_escape",
|
|
3138
|
+
`directory parent is a symlink: ${parent}`,
|
|
3139
|
+
{ hint: "re-resolve the target after detecting symlink swaps" }
|
|
3140
|
+
);
|
|
3141
|
+
}
|
|
3142
|
+
}, "assertParentNotSymlink");
|
|
3143
|
+
try {
|
|
3144
|
+
await assertRealDirectory(target);
|
|
3145
|
+
return;
|
|
3146
|
+
} catch (err) {
|
|
3147
|
+
if (isFsError(err)) throw err;
|
|
3148
|
+
if (err.code !== "ENOENT") throw err;
|
|
3149
|
+
}
|
|
3150
|
+
if (!opts.recursive) {
|
|
3151
|
+
opts.assertGenerationOpen();
|
|
3152
|
+
await assertParentNotSymlink(target);
|
|
3153
|
+
try {
|
|
3154
|
+
await fsp2.mkdir(target, { mode: 493 });
|
|
3155
|
+
} catch (err) {
|
|
3156
|
+
if (err.code !== "EEXIST") throw err;
|
|
3157
|
+
}
|
|
3158
|
+
await assertRealDirectory(target);
|
|
3159
|
+
return;
|
|
3160
|
+
}
|
|
3161
|
+
const missing = [];
|
|
3162
|
+
let current = target;
|
|
3163
|
+
while (true) {
|
|
3164
|
+
try {
|
|
3165
|
+
await assertRealDirectory(current);
|
|
3166
|
+
break;
|
|
3167
|
+
} catch (err) {
|
|
3168
|
+
if (isFsError(err)) throw err;
|
|
3169
|
+
if (err.code !== "ENOENT") throw err;
|
|
3170
|
+
missing.push(current);
|
|
3171
|
+
const parent = path4.dirname(current);
|
|
3172
|
+
if (parent === current) throw err;
|
|
3173
|
+
current = parent;
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
for (const entry of missing.reverse()) {
|
|
3177
|
+
opts.assertGenerationOpen();
|
|
3178
|
+
await assertParentNotSymlink(entry);
|
|
3179
|
+
try {
|
|
3180
|
+
await fsp2.mkdir(entry, { mode: 493 });
|
|
3181
|
+
} catch (err) {
|
|
3182
|
+
if (err.code !== "EEXIST") throw err;
|
|
3183
|
+
}
|
|
3184
|
+
await assertRealDirectory(entry);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
__name(ensureResolvedDirectory, "ensureResolvedDirectory");
|
|
2639
3188
|
async function atomicPublishResolvedFile(input) {
|
|
2640
3189
|
const target = input.target;
|
|
2641
3190
|
const parent = path4.dirname(target);
|
|
@@ -2651,7 +3200,7 @@ async function atomicPublishResolvedFile(input) {
|
|
|
2651
3200
|
`parent path is not a directory: ${parent}`
|
|
2652
3201
|
);
|
|
2653
3202
|
}
|
|
2654
|
-
const tmpSuffix = `.${process.pid}.${
|
|
3203
|
+
const tmpSuffix = `.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`;
|
|
2655
3204
|
const tmpNameMaxBytes = 255;
|
|
2656
3205
|
const tmpBaseMaxBytes = tmpNameMaxBytes - 1 - Buffer.byteLength(tmpSuffix, "utf-8");
|
|
2657
3206
|
let tmpBase = path4.basename(target);
|
|
@@ -2679,7 +3228,10 @@ async function atomicPublishResolvedFile(input) {
|
|
|
2679
3228
|
mode: input.mode,
|
|
2680
3229
|
expectedHash: input.expectedHash
|
|
2681
3230
|
});
|
|
2682
|
-
await chmodHandleBestEffort(
|
|
3231
|
+
await chmodHandleBestEffort(
|
|
3232
|
+
tempHandle,
|
|
3233
|
+
targetState.mode ?? input.newFileModeBits ?? OWNER_ONLY_NEW_FILE_MODE
|
|
3234
|
+
);
|
|
2683
3235
|
await assertTempPathMatchesStat(tmpPath, tempStat);
|
|
2684
3236
|
await tempHandle.close();
|
|
2685
3237
|
tempHandle = void 0;
|
|
@@ -4658,7 +5210,7 @@ __name(registerWorkspaceQualifiedVoiceRoutes, "registerWorkspaceQualifiedVoiceRo
|
|
|
4658
5210
|
|
|
4659
5211
|
// packages/cli/src/serve/workspace-remember.ts
|
|
4660
5212
|
init_esbuild_shims();
|
|
4661
|
-
import { randomUUID } from "node:crypto";
|
|
5213
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4662
5214
|
var debugLogger = createDebugLogger("WORKSPACE_REMEMBER");
|
|
4663
5215
|
function requireTrustedWorkspace(deps, res) {
|
|
4664
5216
|
if (deps.isWorkspaceTrusted?.() !== false) return true;
|
|
@@ -4688,7 +5240,7 @@ function nowIso() {
|
|
|
4688
5240
|
}
|
|
4689
5241
|
__name(nowIso, "nowIso");
|
|
4690
5242
|
function createMemoryTaskId(kind) {
|
|
4691
|
-
return `${kind}-${
|
|
5243
|
+
return `${kind}-${randomUUID2()}`;
|
|
4692
5244
|
}
|
|
4693
5245
|
__name(createMemoryTaskId, "createMemoryTaskId");
|
|
4694
5246
|
function touchedScopesFromTopics(topics) {
|
|
@@ -8114,6 +8666,7 @@ async function deleteDaemonSessionIfOrphan(params) {
|
|
|
8114
8666
|
if (result.kind === "error") {
|
|
8115
8667
|
throw result.error;
|
|
8116
8668
|
}
|
|
8669
|
+
bridge.markSessionCatalogChanged();
|
|
8117
8670
|
return true;
|
|
8118
8671
|
}
|
|
8119
8672
|
__name(deleteDaemonSessionIfOrphan, "deleteDaemonSessionIfOrphan");
|
|
@@ -9231,11 +9784,20 @@ var AcpDispatcher = class {
|
|
|
9231
9784
|
archiveStates
|
|
9232
9785
|
});
|
|
9233
9786
|
}
|
|
9787
|
+
// Combined invalidate-and-mark for catalog mutations whose conservative
|
|
9788
|
+
// finally-semantics match (delete/archive/unarchive). The revision advance
|
|
9789
|
+
// always follows the cache invalidation so a newly exposed version never
|
|
9790
|
+
// precedes it. Exact no-op paths (e.g. metadata rename) gate the mark on
|
|
9791
|
+
// an actual change via the bridge instead of using this helper.
|
|
9792
|
+
invalidateSessionListsAndMarkCatalog(archiveStates) {
|
|
9793
|
+
this.invalidateSessionLists(archiveStates);
|
|
9794
|
+
this.bridge.markSessionCatalogChanged();
|
|
9795
|
+
}
|
|
9234
9796
|
async runWithSessionListInvalidation(archiveStates, mutation) {
|
|
9235
9797
|
try {
|
|
9236
9798
|
return await mutation();
|
|
9237
9799
|
} finally {
|
|
9238
|
-
this.
|
|
9800
|
+
this.invalidateSessionListsAndMarkCatalog(archiveStates);
|
|
9239
9801
|
}
|
|
9240
9802
|
}
|
|
9241
9803
|
removeOrphanSession(sessionId, removePersistedSession = false, runtime = this.getSessionRuntimeContext()) {
|
|
@@ -10718,6 +11280,7 @@ var AcpDispatcher = class {
|
|
|
10718
11280
|
..."groupId" in params ? { groupId: params["groupId"] } : {},
|
|
10719
11281
|
..."color" in params ? { color: params["color"] } : {}
|
|
10720
11282
|
});
|
|
11283
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
10721
11284
|
this.replyConn(conn, id, { sessionId, ...organization });
|
|
10722
11285
|
});
|
|
10723
11286
|
return;
|
|
@@ -10736,6 +11299,7 @@ var AcpDispatcher = class {
|
|
|
10736
11299
|
name: params["name"],
|
|
10737
11300
|
color: params["color"]
|
|
10738
11301
|
});
|
|
11302
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
10739
11303
|
assertGenerationOpen?.();
|
|
10740
11304
|
this.replyConn(conn, id, { group });
|
|
10741
11305
|
return;
|
|
@@ -10753,6 +11317,7 @@ var AcpDispatcher = class {
|
|
|
10753
11317
|
..."color" in params ? { color: params["color"] } : {},
|
|
10754
11318
|
..."order" in params ? { order: params["order"] } : {}
|
|
10755
11319
|
});
|
|
11320
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
10756
11321
|
assertGenerationOpen?.();
|
|
10757
11322
|
this.replyConn(conn, id, { group });
|
|
10758
11323
|
return;
|
|
@@ -10766,6 +11331,9 @@ var AcpDispatcher = class {
|
|
|
10766
11331
|
const deleted = await createSessionOrganizationService(workspaceCwd).deleteGroup(
|
|
10767
11332
|
groupId
|
|
10768
11333
|
);
|
|
11334
|
+
if (deleted) {
|
|
11335
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
11336
|
+
}
|
|
10769
11337
|
assertGenerationOpen?.();
|
|
10770
11338
|
this.replyConn(conn, id, { deleted });
|
|
10771
11339
|
return;
|
|
@@ -12869,7 +13437,7 @@ var AcpDispatcher = class {
|
|
|
12869
13437
|
|
|
12870
13438
|
// packages/cli/src/serve/acp-http/connection-registry.ts
|
|
12871
13439
|
init_esbuild_shims();
|
|
12872
|
-
import { randomUUID as
|
|
13440
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
12873
13441
|
var DEFAULT_MAX_CONNECTIONS = 64;
|
|
12874
13442
|
var AcpConnection = class {
|
|
12875
13443
|
constructor(connectionId, fromLoopback, onAbandonPending, onDetachSession, preAttachBudget = new AcpPreAttachBudget(), onFatalConnection, maxFramesPerConnection = ACP_PRE_ATTACH_MAX_FRAMES_PER_CONNECTION, maxPayloadBytesPerConnection = ACP_PRE_ATTACH_MAX_PAYLOAD_BYTES_PER_CONNECTION, onPreAttachGuardFailure) {
|
|
@@ -12880,8 +13448,8 @@ var AcpConnection = class {
|
|
|
12880
13448
|
this.maxFramesPerConnection = maxFramesPerConnection;
|
|
12881
13449
|
this.maxPayloadBytesPerConnection = maxPayloadBytesPerConnection;
|
|
12882
13450
|
this.onPreAttachGuardFailure = onPreAttachGuardFailure;
|
|
12883
|
-
this.connectionId = connectionId ??
|
|
12884
|
-
this.clientId =
|
|
13451
|
+
this.connectionId = connectionId ?? randomUUID3();
|
|
13452
|
+
this.clientId = randomUUID3();
|
|
12885
13453
|
this.fromLoopback = fromLoopback;
|
|
12886
13454
|
}
|
|
12887
13455
|
static {
|
|
@@ -15985,9 +16553,15 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
15985
16553
|
}
|
|
15986
16554
|
let wss;
|
|
15987
16555
|
let upgradeListener;
|
|
15988
|
-
|
|
16556
|
+
const upgradeServers = /* @__PURE__ */ new Set();
|
|
16557
|
+
const upgradeCredentials = opts.credentials ?? singleTokenCredentials(opts.token);
|
|
15989
16558
|
function setupWebSocket(httpServer) {
|
|
15990
|
-
if (disposed ||
|
|
16559
|
+
if (disposed || upgradeServers.has(httpServer)) return;
|
|
16560
|
+
if (wss) {
|
|
16561
|
+
upgradeServers.add(httpServer);
|
|
16562
|
+
httpServer.on("upgrade", upgradeListener);
|
|
16563
|
+
return;
|
|
16564
|
+
}
|
|
15991
16565
|
wss = new import_websocket_server.default({
|
|
15992
16566
|
noServer: true,
|
|
15993
16567
|
maxPayload: 10 * 1024 * 1024,
|
|
@@ -16007,8 +16581,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16007
16581
|
return false;
|
|
16008
16582
|
}, "handleProtocols")
|
|
16009
16583
|
});
|
|
16010
|
-
|
|
16011
|
-
const expectedTokenHash = opts.token ? createHash3("sha256").update(opts.token).digest() : void 0;
|
|
16584
|
+
upgradeServers.add(httpServer);
|
|
16012
16585
|
upgradeListener = /* @__PURE__ */ __name((req, socket, head) => {
|
|
16013
16586
|
if (disposed) {
|
|
16014
16587
|
socket.destroy();
|
|
@@ -16036,8 +16609,18 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16036
16609
|
return;
|
|
16037
16610
|
}
|
|
16038
16611
|
const fromLoopback = isLoopbackSocket(socket);
|
|
16039
|
-
|
|
16040
|
-
|
|
16612
|
+
const upgradeListenerIdentity = listenerIdentityOfSocket(socket);
|
|
16613
|
+
const host = (req.headers["host"] ?? "").toLowerCase();
|
|
16614
|
+
if (upgradeListenerIdentity.kind === "local-control") {
|
|
16615
|
+
const authority = upgradeListenerIdentity.authority;
|
|
16616
|
+
const browserHost = upgradeListenerIdentity.origin === void 0 ? void 0 : new URL(upgradeListenerIdentity.origin).host.toLowerCase();
|
|
16617
|
+
if (authority === void 0 || host !== authority && host !== browserHost) {
|
|
16618
|
+
logReject(`host-not-allowed ${host || "(missing)"}`);
|
|
16619
|
+
socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
|
|
16620
|
+
socket.destroy();
|
|
16621
|
+
return;
|
|
16622
|
+
}
|
|
16623
|
+
} else if (fromLoopback) {
|
|
16041
16624
|
const allowed = /* @__PURE__ */ new Set([
|
|
16042
16625
|
`localhost:${localPort}`,
|
|
16043
16626
|
`127.0.0.1:${localPort}`,
|
|
@@ -16062,7 +16645,8 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16062
16645
|
try {
|
|
16063
16646
|
const isLoopbackOrigin = isSameLoopbackOrigin(origin, localPort);
|
|
16064
16647
|
const isAllowlistedOrigin = opts.allowedOrigins !== void 0 && opts.allowedOrigins.origins.has(origin.toLowerCase());
|
|
16065
|
-
|
|
16648
|
+
const isListenerOrigin = upgradeListenerIdentity.kind === "local-control" && upgradeListenerIdentity.origin === origin.toLowerCase();
|
|
16649
|
+
if (!isLoopbackOrigin && !isAllowlistedOrigin && !isListenerOrigin) {
|
|
16066
16650
|
logReject(`origin-not-allowed ${origin}`);
|
|
16067
16651
|
socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
|
|
16068
16652
|
socket.destroy();
|
|
@@ -16075,10 +16659,9 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16075
16659
|
return;
|
|
16076
16660
|
}
|
|
16077
16661
|
}
|
|
16078
|
-
if (
|
|
16079
|
-
const
|
|
16080
|
-
|
|
16081
|
-
if (!actual || !expectedTokenHash || actual.length !== expectedTokenHash.length || !timingSafeEqual(expectedTokenHash, actual)) {
|
|
16662
|
+
if (!upgradeCredentials.isOpen(upgradeListenerIdentity)) {
|
|
16663
|
+
const presented = extractUpgradeBearer(req);
|
|
16664
|
+
if (!presented || !upgradeCredentials.verify(presented, upgradeListenerIdentity)) {
|
|
16082
16665
|
logReject("auth-mismatch");
|
|
16083
16666
|
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
16084
16667
|
socket.destroy();
|
|
@@ -16587,10 +17170,12 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16587
17170
|
dispose: /* @__PURE__ */ __name(() => {
|
|
16588
17171
|
if (disposed) return;
|
|
16589
17172
|
disposed = true;
|
|
16590
|
-
if (
|
|
16591
|
-
|
|
17173
|
+
if (upgradeListener) {
|
|
17174
|
+
for (const server of upgradeServers) {
|
|
17175
|
+
server.removeListener("upgrade", upgradeListener);
|
|
17176
|
+
}
|
|
17177
|
+
upgradeServers.clear();
|
|
16592
17178
|
upgradeListener = void 0;
|
|
16593
|
-
upgradeServer = void 0;
|
|
16594
17179
|
}
|
|
16595
17180
|
registry.dispose();
|
|
16596
17181
|
opts.workspaceRememberLane.dispose();
|
|
@@ -16730,6 +17315,17 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16730
17315
|
}, "getSnapshot"),
|
|
16731
17316
|
attachServer(server) {
|
|
16732
17317
|
setupWebSocket(server);
|
|
17318
|
+
},
|
|
17319
|
+
detachServer(server) {
|
|
17320
|
+
if (!upgradeServers.delete(server)) return;
|
|
17321
|
+
if (upgradeListener) server.removeListener("upgrade", upgradeListener);
|
|
17322
|
+
if (!wss) return;
|
|
17323
|
+
for (const client of wss.clients) {
|
|
17324
|
+
const clientSocket = client._socket;
|
|
17325
|
+
if (clientSocket?.server === server) {
|
|
17326
|
+
client.terminate();
|
|
17327
|
+
}
|
|
17328
|
+
}
|
|
16733
17329
|
}
|
|
16734
17330
|
};
|
|
16735
17331
|
}
|
|
@@ -20777,6 +21373,7 @@ __name(registerWorkspaceQualifiedFileWriteRoutes, "registerWorkspaceQualifiedFil
|
|
|
20777
21373
|
var MAX_CONCURRENT_UPLOADS = 4;
|
|
20778
21374
|
var MAX_UPLOAD_FILENAME_BYTES = 255;
|
|
20779
21375
|
var NUMBERED_CANDIDATE_CAP = 1e3;
|
|
21376
|
+
var MAX_UPLOAD_DIR_DEPTH = 64;
|
|
20780
21377
|
var uploadGateLeases = /* @__PURE__ */ new WeakMap();
|
|
20781
21378
|
function createUploadConcurrencyGate(max = MAX_CONCURRENT_UPLOADS) {
|
|
20782
21379
|
let active = 0;
|
|
@@ -20934,6 +21531,14 @@ function fileUploadAdmission(deps, opts) {
|
|
|
20934
21531
|
sendParseError(res, ROUTE2, "`path` must name a file");
|
|
20935
21532
|
return;
|
|
20936
21533
|
}
|
|
21534
|
+
if (dir.split("/").filter(Boolean).length > MAX_UPLOAD_DIR_DEPTH) {
|
|
21535
|
+
sendParseError(
|
|
21536
|
+
res,
|
|
21537
|
+
ROUTE2,
|
|
21538
|
+
`directory path exceeds ${MAX_UPLOAD_DIR_DEPTH} components`
|
|
21539
|
+
);
|
|
21540
|
+
return;
|
|
21541
|
+
}
|
|
20937
21542
|
if (queryPath.includes("\0")) {
|
|
20938
21543
|
sendParseError(res, ROUTE2, "path must not contain null bytes");
|
|
20939
21544
|
return;
|
|
@@ -20979,10 +21584,11 @@ function fileUploadAdmission(deps, opts) {
|
|
|
20979
21584
|
dirStat = await fs9.stat(resolvedDir);
|
|
20980
21585
|
} catch (err) {
|
|
20981
21586
|
if (isFsError(err) && err.kind === "path_not_found") {
|
|
20982
|
-
|
|
20983
|
-
|
|
21587
|
+
await fs9.mkdir(resolvedDir, { recursive: true });
|
|
21588
|
+
dirStat = await fs9.stat(resolvedDir);
|
|
21589
|
+
} else {
|
|
21590
|
+
throw err;
|
|
20984
21591
|
}
|
|
20985
|
-
throw err;
|
|
20986
21592
|
}
|
|
20987
21593
|
if (dirStat.kind !== "directory") {
|
|
20988
21594
|
sendParseError(res, ROUTE2, "parent path is not a directory");
|
|
@@ -21531,6 +22137,24 @@ var legacySessionTelemetryRoutes = [
|
|
|
21531
22137
|
attribution: "handler_resolved",
|
|
21532
22138
|
route: "POST /session/:id/continue"
|
|
21533
22139
|
},
|
|
22140
|
+
{
|
|
22141
|
+
method: "POST",
|
|
22142
|
+
path: "/session/:id/media",
|
|
22143
|
+
attribution: "handler_resolved",
|
|
22144
|
+
route: "POST /session/:id/media"
|
|
22145
|
+
},
|
|
22146
|
+
{
|
|
22147
|
+
method: "GET",
|
|
22148
|
+
path: "/session/:id/media/:mediaId",
|
|
22149
|
+
attribution: "handler_resolved",
|
|
22150
|
+
route: "GET /session/:id/media/:mediaId"
|
|
22151
|
+
},
|
|
22152
|
+
{
|
|
22153
|
+
method: "DELETE",
|
|
22154
|
+
path: "/session/:id/media/:mediaId",
|
|
22155
|
+
attribution: "handler_resolved",
|
|
22156
|
+
route: "DELETE /session/:id/media/:mediaId"
|
|
22157
|
+
},
|
|
21534
22158
|
{
|
|
21535
22159
|
method: "POST",
|
|
21536
22160
|
path: "/session/:id/prompt",
|
|
@@ -21651,6 +22275,18 @@ var legacySessionTelemetryRoutes = [
|
|
|
21651
22275
|
attribution: "handler_resolved",
|
|
21652
22276
|
route: "DELETE /session/:id/pending-prompts/:promptId"
|
|
21653
22277
|
},
|
|
22278
|
+
{
|
|
22279
|
+
method: "GET",
|
|
22280
|
+
path: "/session/:id/turns/current",
|
|
22281
|
+
attribution: "handler_resolved",
|
|
22282
|
+
route: "GET /session/:id/turns/current"
|
|
22283
|
+
},
|
|
22284
|
+
{
|
|
22285
|
+
method: "GET",
|
|
22286
|
+
path: "/session/:id/turns/:promptId",
|
|
22287
|
+
attribution: "handler_resolved",
|
|
22288
|
+
route: "GET /session/:id/turns/:promptId"
|
|
22289
|
+
},
|
|
21654
22290
|
{
|
|
21655
22291
|
method: "POST",
|
|
21656
22292
|
path: "/session/:id/shell",
|
|
@@ -21779,6 +22415,9 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
21779
22415
|
if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions$/.test(path19)) {
|
|
21780
22416
|
return { route: "GET /workspace/:id/sessions" };
|
|
21781
22417
|
}
|
|
22418
|
+
if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions\/live-state$/.test(path19)) {
|
|
22419
|
+
return { route: "GET /workspaces/:workspace/sessions/live-state" };
|
|
22420
|
+
}
|
|
21782
22421
|
if (req.method === "GET" && /^\/workspace\/[^/]+\/session-info$/.test(path19)) {
|
|
21783
22422
|
return { route: "GET /workspace/:id/session-info" };
|
|
21784
22423
|
}
|
|
@@ -22212,6 +22851,7 @@ init_esbuild_shims();
|
|
|
22212
22851
|
import * as crypto3 from "node:crypto";
|
|
22213
22852
|
import * as fs6 from "node:fs";
|
|
22214
22853
|
import * as path12 from "node:path";
|
|
22854
|
+
var import_express4 = __toESM(require_express(), 1);
|
|
22215
22855
|
|
|
22216
22856
|
// packages/cli/src/serve/server/prompt-deadline.ts
|
|
22217
22857
|
init_esbuild_shims();
|
|
@@ -24036,6 +24676,45 @@ var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 2 * SESSION_TRANSCRIPT_MAX_EXPANDE
|
|
|
24036
24676
|
var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
|
|
24037
24677
|
var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
|
|
24038
24678
|
var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
|
|
24679
|
+
var MEDIA_CONTENT_MAX_BLOCKS = 256;
|
|
24680
|
+
function isSvgMimeType(mimeType) {
|
|
24681
|
+
return mimeType?.split(";", 1)[0]?.trim().toLowerCase() === "image/svg+xml";
|
|
24682
|
+
}
|
|
24683
|
+
__name(isSvgMimeType, "isSvgMimeType");
|
|
24684
|
+
function parseMediaContentBlock(block) {
|
|
24685
|
+
if (typeof block !== "object" || block === null || Array.isArray(block)) {
|
|
24686
|
+
return { valid: false, code: "not-object" };
|
|
24687
|
+
}
|
|
24688
|
+
const record = block;
|
|
24689
|
+
const type = record["type"];
|
|
24690
|
+
const data = record["data"];
|
|
24691
|
+
const mediaId = record["mediaId"];
|
|
24692
|
+
const mimeType = record["mimeType"];
|
|
24693
|
+
const size = record["size"];
|
|
24694
|
+
const inline = typeof data === "string" && data.length > 0;
|
|
24695
|
+
const reference = typeof mediaId === "string" && mediaId.length > 0 && typeof size === "number" && Number.isSafeInteger(size) && size > 0;
|
|
24696
|
+
if (type !== "image" || inline === reference || typeof mimeType !== "string" || !mimeType.startsWith(`${type}/`)) {
|
|
24697
|
+
return { valid: false, code: "invalid-shape" };
|
|
24698
|
+
}
|
|
24699
|
+
if (isSvgMimeType(mimeType)) {
|
|
24700
|
+
return { valid: false, code: "svg" };
|
|
24701
|
+
}
|
|
24702
|
+
return {
|
|
24703
|
+
valid: true,
|
|
24704
|
+
block: inline ? { type, data, mimeType } : { type, mediaId, mimeType, size }
|
|
24705
|
+
};
|
|
24706
|
+
}
|
|
24707
|
+
__name(parseMediaContentBlock, "parseMediaContentBlock");
|
|
24708
|
+
function mediaBlockParseError(code, entryLabel) {
|
|
24709
|
+
if (code === "not-object") {
|
|
24710
|
+
return `each ${entryLabel} must be a media content block`;
|
|
24711
|
+
}
|
|
24712
|
+
if (code === "svg") {
|
|
24713
|
+
return "SVG images are not supported";
|
|
24714
|
+
}
|
|
24715
|
+
return `each ${entryLabel} must be an image block with either \`data\`, or \`mediaId\` and \`size\`, plus a matching \`mimeType\``;
|
|
24716
|
+
}
|
|
24717
|
+
__name(mediaBlockParseError, "mediaBlockParseError");
|
|
24039
24718
|
var PRIMARY_ONLY_LIVE_SESSION_ROUTES = ["POST /session/:id/cd"];
|
|
24040
24719
|
var PRIMARY_OR_INTERNAL_LIVE_SESSION_ROUTES = [
|
|
24041
24720
|
"POST /session/:id/branch",
|
|
@@ -24243,11 +24922,15 @@ function registerSessionRoutes(app, deps) {
|
|
|
24243
24922
|
archiveStates
|
|
24244
24923
|
});
|
|
24245
24924
|
}, "invalidateSessionLists");
|
|
24925
|
+
const invalidateSessionListsAndMarkCatalog = /* @__PURE__ */ __name((runtime, archiveStates) => {
|
|
24926
|
+
invalidateSessionLists(runtime, archiveStates);
|
|
24927
|
+
runtime.bridge.markSessionCatalogChanged();
|
|
24928
|
+
}, "invalidateSessionListsAndMarkCatalog");
|
|
24246
24929
|
const runWithSessionListInvalidation = /* @__PURE__ */ __name(async (runtime, archiveStates, mutation) => {
|
|
24247
24930
|
try {
|
|
24248
24931
|
return await mutation();
|
|
24249
24932
|
} finally {
|
|
24250
|
-
|
|
24933
|
+
invalidateSessionListsAndMarkCatalog(runtime, archiveStates);
|
|
24251
24934
|
}
|
|
24252
24935
|
}, "runWithSessionListInvalidation");
|
|
24253
24936
|
const requestedSessionIdAdmission = deps.requestedSessionIdAdmission ?? createRequestedSessionIdAdmission({
|
|
@@ -26459,8 +27142,10 @@ function registerSessionRoutes(app, deps) {
|
|
|
26459
27142
|
if (!result.attached) {
|
|
26460
27143
|
const killed = await runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => false);
|
|
26461
27144
|
if (killed) {
|
|
26462
|
-
await createWorkspaceRuntimeSessionService(
|
|
26463
|
-
|
|
27145
|
+
const removed = await createWorkspaceRuntimeSessionService(
|
|
27146
|
+
runtime
|
|
27147
|
+
).removeSession(result.sessionId).catch(() => false);
|
|
27148
|
+
if (removed) runtime.bridge.markSessionCatalogChanged();
|
|
26464
27149
|
}
|
|
26465
27150
|
} else {
|
|
26466
27151
|
await runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
|
|
@@ -26470,11 +27155,12 @@ function registerSessionRoutes(app, deps) {
|
|
|
26470
27155
|
}
|
|
26471
27156
|
if (!res.writable) {
|
|
26472
27157
|
if (!result.attached) {
|
|
26473
|
-
runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then((killed) => {
|
|
26474
|
-
if (!killed) return
|
|
26475
|
-
|
|
27158
|
+
runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then(async (killed) => {
|
|
27159
|
+
if (!killed) return;
|
|
27160
|
+
const removed = await createWorkspaceRuntimeSessionService(
|
|
26476
27161
|
runtime
|
|
26477
27162
|
).removeSession(result.sessionId);
|
|
27163
|
+
if (removed) runtime.bridge.markSessionCatalogChanged();
|
|
26478
27164
|
}).catch(() => {
|
|
26479
27165
|
});
|
|
26480
27166
|
} else {
|
|
@@ -27061,6 +27747,103 @@ function registerSessionRoutes(app, deps) {
|
|
|
27061
27747
|
}
|
|
27062
27748
|
)
|
|
27063
27749
|
);
|
|
27750
|
+
app.post(
|
|
27751
|
+
"/session/:id/media",
|
|
27752
|
+
mutate(),
|
|
27753
|
+
import_express4.default.raw({ type: "image/*", limit: "8mb" }),
|
|
27754
|
+
(error2, _req, res, next) => {
|
|
27755
|
+
if (error2 && typeof error2 === "object" && "status" in error2 && error2.status === 413) {
|
|
27756
|
+
res.status(413).json({ error: "Request body too large (max 8 MiB)" });
|
|
27757
|
+
return;
|
|
27758
|
+
}
|
|
27759
|
+
next(error2);
|
|
27760
|
+
},
|
|
27761
|
+
withOwnerMutableSession(
|
|
27762
|
+
"POST /session/:id/media",
|
|
27763
|
+
async (req, res, sessionId, runtime) => {
|
|
27764
|
+
const contentType = req.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase();
|
|
27765
|
+
if (isSvgMimeType(contentType)) {
|
|
27766
|
+
res.status(415).json({ error: "SVG uploads are not supported" });
|
|
27767
|
+
return;
|
|
27768
|
+
}
|
|
27769
|
+
if (!contentType || !contentType.startsWith("image/") || !Buffer.isBuffer(req.body) || req.body.byteLength === 0) {
|
|
27770
|
+
res.status(400).json({
|
|
27771
|
+
error: "request body must contain image/* bytes with a matching Content-Type"
|
|
27772
|
+
});
|
|
27773
|
+
return;
|
|
27774
|
+
}
|
|
27775
|
+
const clientId = parseClientIdHeader(req, res);
|
|
27776
|
+
if (clientId === null) return;
|
|
27777
|
+
try {
|
|
27778
|
+
const reference = await runtime.bridge.storeSessionMedia(
|
|
27779
|
+
sessionId,
|
|
27780
|
+
req.body,
|
|
27781
|
+
contentType,
|
|
27782
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
27783
|
+
);
|
|
27784
|
+
res.status(201).json(reference);
|
|
27785
|
+
} catch (error2) {
|
|
27786
|
+
if (error2 instanceof RangeError) {
|
|
27787
|
+
res.status(413).json({ error: error2.message });
|
|
27788
|
+
return;
|
|
27789
|
+
}
|
|
27790
|
+
throw error2;
|
|
27791
|
+
}
|
|
27792
|
+
}
|
|
27793
|
+
)
|
|
27794
|
+
);
|
|
27795
|
+
app.get(
|
|
27796
|
+
"/session/:id/media/:mediaId",
|
|
27797
|
+
withOwnerReadSession(
|
|
27798
|
+
"GET /session/:id/media/:mediaId",
|
|
27799
|
+
async (req, res, sessionId, runtime) => {
|
|
27800
|
+
const mediaId = req.params["mediaId"];
|
|
27801
|
+
if (!mediaId) {
|
|
27802
|
+
res.status(400).json({ error: "`mediaId` is required" });
|
|
27803
|
+
return;
|
|
27804
|
+
}
|
|
27805
|
+
const clientId = parseClientIdHeader(req, res);
|
|
27806
|
+
if (clientId === null) return;
|
|
27807
|
+
const media = await runtime.bridge.readSessionMedia(
|
|
27808
|
+
sessionId,
|
|
27809
|
+
mediaId,
|
|
27810
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
27811
|
+
);
|
|
27812
|
+
if (!media) {
|
|
27813
|
+
res.status(404).json({ error: "session media not found" });
|
|
27814
|
+
return;
|
|
27815
|
+
}
|
|
27816
|
+
res.setHeader("Content-Type", media.mimeType);
|
|
27817
|
+
res.setHeader("Content-Length", String(media.data.byteLength));
|
|
27818
|
+
res.setHeader("Cache-Control", "private, max-age=300");
|
|
27819
|
+
res.setHeader("Content-Disposition", "attachment");
|
|
27820
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
27821
|
+
res.status(200).send(media.data);
|
|
27822
|
+
}
|
|
27823
|
+
)
|
|
27824
|
+
);
|
|
27825
|
+
app.delete(
|
|
27826
|
+
"/session/:id/media/:mediaId",
|
|
27827
|
+
mutate(),
|
|
27828
|
+
withOwnerMutableSession(
|
|
27829
|
+
"DELETE /session/:id/media/:mediaId",
|
|
27830
|
+
async (req, res, sessionId, runtime) => {
|
|
27831
|
+
const mediaId = req.params["mediaId"];
|
|
27832
|
+
if (!mediaId) {
|
|
27833
|
+
res.status(400).json({ error: "`mediaId` is required" });
|
|
27834
|
+
return;
|
|
27835
|
+
}
|
|
27836
|
+
const clientId = parseClientIdHeader(req, res);
|
|
27837
|
+
if (clientId === null) return;
|
|
27838
|
+
const removed = await runtime.bridge.removeSessionMedia(
|
|
27839
|
+
sessionId,
|
|
27840
|
+
mediaId,
|
|
27841
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
27842
|
+
);
|
|
27843
|
+
res.status(200).json({ removed });
|
|
27844
|
+
}
|
|
27845
|
+
)
|
|
27846
|
+
);
|
|
27064
27847
|
app.post(
|
|
27065
27848
|
"/session/:id/prompt",
|
|
27066
27849
|
mutate(),
|
|
@@ -27084,6 +27867,25 @@ function registerSessionRoutes(app, deps) {
|
|
|
27084
27867
|
});
|
|
27085
27868
|
return;
|
|
27086
27869
|
}
|
|
27870
|
+
const mediaBlockCount = prompt.filter(
|
|
27871
|
+
(item) => item["type"] !== "text"
|
|
27872
|
+
).length;
|
|
27873
|
+
if (mediaBlockCount > MEDIA_CONTENT_MAX_BLOCKS) {
|
|
27874
|
+
res.status(400).json({
|
|
27875
|
+
error: `\`prompt\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
|
|
27876
|
+
});
|
|
27877
|
+
return;
|
|
27878
|
+
}
|
|
27879
|
+
for (const item of prompt) {
|
|
27880
|
+
if (item["type"] !== "image") continue;
|
|
27881
|
+
const parsed = parseMediaContentBlock(item);
|
|
27882
|
+
if (!parsed.valid) {
|
|
27883
|
+
res.status(400).json({
|
|
27884
|
+
error: mediaBlockParseError(parsed.code, "`prompt` image block")
|
|
27885
|
+
});
|
|
27886
|
+
return;
|
|
27887
|
+
}
|
|
27888
|
+
}
|
|
27087
27889
|
const rawRequestDeadline = body["deadlineMs"];
|
|
27088
27890
|
let requestDeadlineMs;
|
|
27089
27891
|
if (rawRequestDeadline !== void 0 && rawRequestDeadline !== null) {
|
|
@@ -27638,6 +28440,113 @@ function registerSessionRoutes(app, deps) {
|
|
|
27638
28440
|
}
|
|
27639
28441
|
)
|
|
27640
28442
|
);
|
|
28443
|
+
app.patch(
|
|
28444
|
+
"/workspaces/:workspace/session/:id/metadata",
|
|
28445
|
+
mutate({ strict: true }),
|
|
28446
|
+
async (req, res) => {
|
|
28447
|
+
const route = "PATCH /workspaces/:workspace/session/:id/metadata";
|
|
28448
|
+
const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
|
|
28449
|
+
if (!runtime) return;
|
|
28450
|
+
const sessionId = requireSessionId(req, res);
|
|
28451
|
+
if (sessionId === null) return;
|
|
28452
|
+
const clientId = parseClientIdHeader(req, res);
|
|
28453
|
+
if (clientId === null) return;
|
|
28454
|
+
const rawDisplayName = safeBody(req)["displayName"];
|
|
28455
|
+
if (typeof rawDisplayName !== "string") {
|
|
28456
|
+
res.status(400).json({
|
|
28457
|
+
error: "`displayName` must be a string",
|
|
28458
|
+
code: "invalid_metadata",
|
|
28459
|
+
field: "displayName"
|
|
28460
|
+
});
|
|
28461
|
+
return;
|
|
28462
|
+
}
|
|
28463
|
+
try {
|
|
28464
|
+
const displayName = rawDisplayName.slice(0, 256);
|
|
28465
|
+
if (displayName.trim() === "") {
|
|
28466
|
+
throw new InvalidSessionMetadataError(
|
|
28467
|
+
"displayName",
|
|
28468
|
+
"must not be empty"
|
|
28469
|
+
);
|
|
28470
|
+
}
|
|
28471
|
+
if (Array.from(displayName).some((character) => {
|
|
28472
|
+
const code = character.charCodeAt(0);
|
|
28473
|
+
return code <= 31 || code === 127;
|
|
28474
|
+
})) {
|
|
28475
|
+
throw new InvalidSessionMetadataError(
|
|
28476
|
+
"displayName",
|
|
28477
|
+
"must not contain control characters"
|
|
28478
|
+
);
|
|
28479
|
+
}
|
|
28480
|
+
await archiveCoordinator.runExclusiveMany([sessionId], async () => {
|
|
28481
|
+
const assertRuntimeGenerationOpen = captureRuntimeGenerationAssertion(runtime);
|
|
28482
|
+
assertRuntimeGenerationOpen?.();
|
|
28483
|
+
const liveOwner = workspaceRegistry.resolveLiveSessionOwner(sessionId);
|
|
28484
|
+
if (liveOwner.kind === "unavailable") {
|
|
28485
|
+
sendWorkspaceRuntimeUnavailable(res);
|
|
28486
|
+
return;
|
|
28487
|
+
}
|
|
28488
|
+
if (liveOwner.kind === "ambiguous") {
|
|
28489
|
+
sendAmbiguousSessionOwner(
|
|
28490
|
+
res,
|
|
28491
|
+
route,
|
|
28492
|
+
sessionId,
|
|
28493
|
+
liveOwner.runtimes
|
|
28494
|
+
);
|
|
28495
|
+
return;
|
|
28496
|
+
}
|
|
28497
|
+
if (liveOwner.kind === "found" && liveOwner.runtime.workspaceCwd !== runtime.workspaceCwd) {
|
|
28498
|
+
sendSessionWorkspaceConflict(
|
|
28499
|
+
res,
|
|
28500
|
+
route,
|
|
28501
|
+
sessionId,
|
|
28502
|
+
runtime,
|
|
28503
|
+
liveOwner.runtime
|
|
28504
|
+
);
|
|
28505
|
+
return;
|
|
28506
|
+
}
|
|
28507
|
+
await runWithWorkspaceRuntimeStorage(runtime, async () => {
|
|
28508
|
+
let effective;
|
|
28509
|
+
try {
|
|
28510
|
+
effective = runtime.bridge.updateSessionMetadata(
|
|
28511
|
+
sessionId,
|
|
28512
|
+
{ displayName },
|
|
28513
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
28514
|
+
);
|
|
28515
|
+
assertRuntimeGenerationOpen?.();
|
|
28516
|
+
} catch (err) {
|
|
28517
|
+
if (!(err instanceof SessionNotFoundError)) throw err;
|
|
28518
|
+
const service = createWorkspaceRuntimeSessionService(runtime);
|
|
28519
|
+
const location = await service.getSessionLocation(sessionId);
|
|
28520
|
+
assertRuntimeGenerationOpen?.();
|
|
28521
|
+
if (location === "conflict") {
|
|
28522
|
+
throw new SessionConflictError(sessionId);
|
|
28523
|
+
}
|
|
28524
|
+
const renamed = location ? await service.renameSession(
|
|
28525
|
+
sessionId,
|
|
28526
|
+
displayName,
|
|
28527
|
+
"manual",
|
|
28528
|
+
location
|
|
28529
|
+
) : false;
|
|
28530
|
+
assertRuntimeGenerationOpen?.();
|
|
28531
|
+
if (!renamed) {
|
|
28532
|
+
throw new SessionNotFoundError(sessionId);
|
|
28533
|
+
}
|
|
28534
|
+
runtime.bridge.markSessionCatalogChanged();
|
|
28535
|
+
effective = { displayName: displayName || void 0 };
|
|
28536
|
+
}
|
|
28537
|
+
invalidateSessionLists(runtime, ["active", "archived"]);
|
|
28538
|
+
res.status(200).json({ sessionId, ...effective });
|
|
28539
|
+
});
|
|
28540
|
+
});
|
|
28541
|
+
} catch (err) {
|
|
28542
|
+
sendBridgeError2(res, err, {
|
|
28543
|
+
route,
|
|
28544
|
+
sessionId,
|
|
28545
|
+
workspaceCwd: runtime.workspaceCwd
|
|
28546
|
+
});
|
|
28547
|
+
}
|
|
28548
|
+
}
|
|
28549
|
+
);
|
|
27641
28550
|
const handleSessionOrganizationUpdate = /* @__PURE__ */ __name(async (req, res, target) => {
|
|
27642
28551
|
const sessionId = requireSessionId(req, res);
|
|
27643
28552
|
if (sessionId === null) return;
|
|
@@ -27705,6 +28614,10 @@ function registerSessionRoutes(app, deps) {
|
|
|
27705
28614
|
...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
|
|
27706
28615
|
...rawColor !== void 0 ? { color: rawColor } : {}
|
|
27707
28616
|
});
|
|
28617
|
+
invalidateSessionListsAndMarkCatalog(runtime, [
|
|
28618
|
+
"active",
|
|
28619
|
+
"archived"
|
|
28620
|
+
]);
|
|
27708
28621
|
res.status(200).json({ sessionId, ...organization });
|
|
27709
28622
|
});
|
|
27710
28623
|
})()
|
|
@@ -27767,6 +28680,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27767
28680
|
color: body["color"]
|
|
27768
28681
|
})
|
|
27769
28682
|
);
|
|
28683
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27770
28684
|
res.status(201).json({ group });
|
|
27771
28685
|
} catch (err) {
|
|
27772
28686
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27794,6 +28708,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27794
28708
|
}
|
|
27795
28709
|
)
|
|
27796
28710
|
);
|
|
28711
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27797
28712
|
res.status(200).json({ group });
|
|
27798
28713
|
} catch (err) {
|
|
27799
28714
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27816,6 +28731,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
27816
28731
|
req.params["groupId"] ?? ""
|
|
27817
28732
|
)
|
|
27818
28733
|
);
|
|
28734
|
+
if (deleted) {
|
|
28735
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
28736
|
+
}
|
|
27819
28737
|
res.status(200).json({ deleted });
|
|
27820
28738
|
} catch (err) {
|
|
27821
28739
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27856,6 +28774,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27856
28774
|
color: body["color"]
|
|
27857
28775
|
})
|
|
27858
28776
|
);
|
|
28777
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27859
28778
|
res.status(201).json({ group });
|
|
27860
28779
|
} catch (err) {
|
|
27861
28780
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27883,6 +28802,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27883
28802
|
}
|
|
27884
28803
|
)
|
|
27885
28804
|
);
|
|
28805
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27886
28806
|
res.status(200).json({ group });
|
|
27887
28807
|
} catch (err) {
|
|
27888
28808
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27904,6 +28824,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
27904
28824
|
req.params["groupId"] ?? ""
|
|
27905
28825
|
)
|
|
27906
28826
|
);
|
|
28827
|
+
if (deleted) {
|
|
28828
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
28829
|
+
}
|
|
27907
28830
|
res.status(200).json({ deleted });
|
|
27908
28831
|
} catch (err) {
|
|
27909
28832
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -28089,6 +29012,35 @@ function registerSessionRoutes(app, deps) {
|
|
|
28089
29012
|
"/workspaces/:workspace/sessions",
|
|
28090
29013
|
listWorkspaceSessionsHandler("workspace")
|
|
28091
29014
|
);
|
|
29015
|
+
const lastExposedCatalogVersions = /* @__PURE__ */ new WeakMap();
|
|
29016
|
+
app.get("/workspaces/:workspace/sessions/live-state", async (req, res) => {
|
|
29017
|
+
const route = "GET /workspaces/:workspace/sessions/live-state";
|
|
29018
|
+
const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
|
|
29019
|
+
if (runtime === null) return;
|
|
29020
|
+
const assertRuntimeOpen = captureRuntimeGenerationAssertion(runtime);
|
|
29021
|
+
const bridge = runtime.bridge;
|
|
29022
|
+
try {
|
|
29023
|
+
assertRuntimeOpen?.();
|
|
29024
|
+
const catalogVersion = bridge.getSessionCatalogVersion();
|
|
29025
|
+
const lastExposed = lastExposedCatalogVersions.get(bridge);
|
|
29026
|
+
if (lastExposed === void 0 || lastExposed.generation !== catalogVersion.generation || lastExposed.revision !== catalogVersion.revision) {
|
|
29027
|
+
invalidateSessionLists(runtime, ["active", "archived"]);
|
|
29028
|
+
}
|
|
29029
|
+
const sessions = bridge.listWorkspaceSessions(runtime.workspaceCwd).map((session) => ({
|
|
29030
|
+
sessionId: session.sessionId,
|
|
29031
|
+
clientCount: session.clientCount,
|
|
29032
|
+
hasActivePrompt: session.hasActivePrompt,
|
|
29033
|
+
isWaitingForPermission: session.isWaitingForPermission ?? false,
|
|
29034
|
+
isWaitingForUserQuestion: session.isWaitingForUserQuestion ?? false
|
|
29035
|
+
}));
|
|
29036
|
+
assertRuntimeOpen?.();
|
|
29037
|
+
lastExposedCatalogVersions.set(bridge, catalogVersion);
|
|
29038
|
+
res.setHeader("Cache-Control", "no-store");
|
|
29039
|
+
res.status(200).json({ v: 1, catalogVersion, sessions });
|
|
29040
|
+
} catch (err) {
|
|
29041
|
+
sendBridgeError2(res, err, { route });
|
|
29042
|
+
}
|
|
29043
|
+
});
|
|
28092
29044
|
const workspaceSessionInfoHandler = /* @__PURE__ */ __name((paramName) => async (req, res) => {
|
|
28093
29045
|
const route = paramName === "workspace" ? "GET /workspaces/:workspace/session-info" : "GET /workspace/:id/session-info";
|
|
28094
29046
|
const runtime = resolveRuntimeForCatalogRoute(req, res, paramName, route);
|
|
@@ -28257,9 +29209,36 @@ function registerSessionRoutes(app, deps) {
|
|
|
28257
29209
|
const message = body["message"];
|
|
28258
29210
|
const messageId = body["messageId"];
|
|
28259
29211
|
const trimmed = typeof message === "string" ? message.trim() : "";
|
|
28260
|
-
|
|
29212
|
+
const rawContent = body["content"];
|
|
29213
|
+
let mediaBlocks;
|
|
29214
|
+
if (rawContent !== void 0) {
|
|
29215
|
+
if (!Array.isArray(rawContent) || rawContent.length === 0) {
|
|
29216
|
+
res.status(400).json({
|
|
29217
|
+
error: "`content` must be a non-empty array of media blocks"
|
|
29218
|
+
});
|
|
29219
|
+
return;
|
|
29220
|
+
}
|
|
29221
|
+
if (rawContent.length > MEDIA_CONTENT_MAX_BLOCKS) {
|
|
29222
|
+
res.status(400).json({
|
|
29223
|
+
error: `\`content\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
|
|
29224
|
+
});
|
|
29225
|
+
return;
|
|
29226
|
+
}
|
|
29227
|
+
mediaBlocks = [];
|
|
29228
|
+
for (const block of rawContent) {
|
|
29229
|
+
const parsed = parseMediaContentBlock(block);
|
|
29230
|
+
if (!parsed.valid) {
|
|
29231
|
+
res.status(400).json({
|
|
29232
|
+
error: mediaBlockParseError(parsed.code, "`content` entry")
|
|
29233
|
+
});
|
|
29234
|
+
return;
|
|
29235
|
+
}
|
|
29236
|
+
mediaBlocks.push(parsed.block);
|
|
29237
|
+
}
|
|
29238
|
+
}
|
|
29239
|
+
if (trimmed.length === 0 && mediaBlocks === void 0) {
|
|
28261
29240
|
res.status(400).json({
|
|
28262
|
-
error: "`message`
|
|
29241
|
+
error: "`message` must be a non-empty string, or `content` must carry at least one media block"
|
|
28263
29242
|
});
|
|
28264
29243
|
return;
|
|
28265
29244
|
}
|
|
@@ -28281,7 +29260,8 @@ function registerSessionRoutes(app, deps) {
|
|
|
28281
29260
|
sessionId,
|
|
28282
29261
|
trimmed,
|
|
28283
29262
|
clientId !== void 0 ? { clientId } : void 0,
|
|
28284
|
-
typeof messageId === "string" ? messageId : void 0
|
|
29263
|
+
typeof messageId === "string" ? messageId : void 0,
|
|
29264
|
+
mediaBlocks ? { content: mediaBlocks } : void 0
|
|
28285
29265
|
);
|
|
28286
29266
|
res.status(200).json(result);
|
|
28287
29267
|
}
|
|
@@ -28373,6 +29353,73 @@ function registerSessionRoutes(app, deps) {
|
|
|
28373
29353
|
}
|
|
28374
29354
|
)
|
|
28375
29355
|
);
|
|
29356
|
+
app.get("/session/:id/turns/current", (req, res) => {
|
|
29357
|
+
const sessionId = requireSessionId(req, res);
|
|
29358
|
+
if (sessionId === null) return;
|
|
29359
|
+
const runtime = resolveLiveSessionRuntime(
|
|
29360
|
+
sessionId,
|
|
29361
|
+
res,
|
|
29362
|
+
"GET /session/:id/turns/current"
|
|
29363
|
+
);
|
|
29364
|
+
if (!runtime) return;
|
|
29365
|
+
const clientId = parseClientIdHeader(req, res);
|
|
29366
|
+
if (clientId === null) return;
|
|
29367
|
+
void (async () => {
|
|
29368
|
+
try {
|
|
29369
|
+
const status = await runtime.bridge.getSessionTurnStatus(
|
|
29370
|
+
sessionId,
|
|
29371
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
29372
|
+
);
|
|
29373
|
+
res.status(200).json(status);
|
|
29374
|
+
} catch (err) {
|
|
29375
|
+
sendBridgeError2(res, err, {
|
|
29376
|
+
route: "GET /session/:id/turns/current",
|
|
29377
|
+
sessionId
|
|
29378
|
+
});
|
|
29379
|
+
}
|
|
29380
|
+
})();
|
|
29381
|
+
});
|
|
29382
|
+
app.get("/session/:id/turns/:promptId", (req, res) => {
|
|
29383
|
+
const sessionId = requireSessionId(req, res);
|
|
29384
|
+
if (sessionId === null) return;
|
|
29385
|
+
const runtime = resolveLiveSessionRuntime(
|
|
29386
|
+
sessionId,
|
|
29387
|
+
res,
|
|
29388
|
+
"GET /session/:id/turns/:promptId"
|
|
29389
|
+
);
|
|
29390
|
+
if (!runtime) return;
|
|
29391
|
+
const promptId = req.params["promptId"];
|
|
29392
|
+
if (!promptId) {
|
|
29393
|
+
res.status(400).json({ error: "`promptId` route parameter is required" });
|
|
29394
|
+
return;
|
|
29395
|
+
}
|
|
29396
|
+
const clientId = parseClientIdHeader(req, res);
|
|
29397
|
+
if (clientId === null) return;
|
|
29398
|
+
void (async () => {
|
|
29399
|
+
try {
|
|
29400
|
+
const status = await runtime.bridge.getSessionTurnStatus(
|
|
29401
|
+
sessionId,
|
|
29402
|
+
clientId !== void 0 ? { clientId } : void 0,
|
|
29403
|
+
promptId
|
|
29404
|
+
);
|
|
29405
|
+
if (!status) {
|
|
29406
|
+
res.status(404).json({
|
|
29407
|
+
error: `Prompt ${promptId} not found in session ${sessionId}`,
|
|
29408
|
+
code: "prompt_not_found",
|
|
29409
|
+
sessionId,
|
|
29410
|
+
promptId
|
|
29411
|
+
});
|
|
29412
|
+
return;
|
|
29413
|
+
}
|
|
29414
|
+
res.status(200).json(status);
|
|
29415
|
+
} catch (err) {
|
|
29416
|
+
sendBridgeError2(res, err, {
|
|
29417
|
+
route: "GET /session/:id/turns/:promptId",
|
|
29418
|
+
sessionId
|
|
29419
|
+
});
|
|
29420
|
+
}
|
|
29421
|
+
})();
|
|
29422
|
+
});
|
|
28376
29423
|
app.post(
|
|
28377
29424
|
"/session/:id/shell",
|
|
28378
29425
|
mutate({ strict: true }),
|
|
@@ -28634,10 +29681,10 @@ async function teardownBoundSession(target, sessionId) {
|
|
|
28634
29681
|
} else if (target.bridge) {
|
|
28635
29682
|
await target.bridge.closeSession(sessionId).catch(() => {
|
|
28636
29683
|
});
|
|
28637
|
-
await new SessionService(target.workspaceCwd, {
|
|
29684
|
+
const removed = await new SessionService(target.workspaceCwd, {
|
|
28638
29685
|
runtimeBaseDir: target.runtimeBaseDir
|
|
28639
|
-
}).removeSession(sessionId).catch(() =>
|
|
28640
|
-
|
|
29686
|
+
}).removeSession(sessionId).catch(() => false);
|
|
29687
|
+
if (removed) target.bridge.markSessionCatalogChanged?.();
|
|
28641
29688
|
}
|
|
28642
29689
|
}
|
|
28643
29690
|
__name(teardownBoundSession, "teardownBoundSession");
|
|
@@ -29523,7 +30570,7 @@ __name(parseNameField, "parseNameField");
|
|
|
29523
30570
|
|
|
29524
30571
|
// packages/cli/src/serve/routes/channel-notify.ts
|
|
29525
30572
|
init_esbuild_shims();
|
|
29526
|
-
import { randomUUID as
|
|
30573
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
29527
30574
|
function sendDeliveryError(res, error2) {
|
|
29528
30575
|
if (!isChannelDeliveryError(error2)) {
|
|
29529
30576
|
res.status(502).json({
|
|
@@ -29544,7 +30591,7 @@ function parseNotifyBody(body) {
|
|
|
29544
30591
|
);
|
|
29545
30592
|
}
|
|
29546
30593
|
return normalizeChannelDelivery(
|
|
29547
|
-
|
|
30594
|
+
randomUUID7(),
|
|
29548
30595
|
parseChannelDelivery(body["delivery"]),
|
|
29549
30596
|
body["text"]
|
|
29550
30597
|
);
|
|
@@ -29863,9 +30910,10 @@ function startScheduledTaskKeepalive(opts) {
|
|
|
29863
30910
|
const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
|
|
29864
30911
|
const cleanupSession = opts.cleanupSession ?? (async (sessionId) => {
|
|
29865
30912
|
await bridge.closeSession(sessionId);
|
|
29866
|
-
await new SessionService(boundWorkspace, {
|
|
30913
|
+
const removed = await new SessionService(boundWorkspace, {
|
|
29867
30914
|
runtimeBaseDir: opts.runtimeBaseDir
|
|
29868
30915
|
}).removeSession(sessionId);
|
|
30916
|
+
if (removed) bridge.markSessionCatalogChanged?.();
|
|
29869
30917
|
});
|
|
29870
30918
|
const reviveState = /* @__PURE__ */ new Map();
|
|
29871
30919
|
const reviving = /* @__PURE__ */ new Set();
|
|
@@ -31443,7 +32491,7 @@ __name(registerWorkspaceQualifiedSettingsRoutes, "registerWorkspaceQualifiedSett
|
|
|
31443
32491
|
|
|
31444
32492
|
// packages/cli/src/serve/routes/sse-events.ts
|
|
31445
32493
|
init_esbuild_shims();
|
|
31446
|
-
import { randomUUID as
|
|
32494
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
31447
32495
|
import { performance as performance2 } from "node:perf_hooks";
|
|
31448
32496
|
|
|
31449
32497
|
// packages/cli/src/serve/server/error-response.ts
|
|
@@ -31561,6 +32609,10 @@ function sendBridgeError(res, err, ctx, daemonLog) {
|
|
|
31561
32609
|
return;
|
|
31562
32610
|
}
|
|
31563
32611
|
if (sendGenerationClosedError(res, err)) return;
|
|
32612
|
+
if (err instanceof Error && "code" in err && (err.code === "session_media_gone" || err.code === "invalid_session_media_reference")) {
|
|
32613
|
+
res.status(err.code === "session_media_gone" ? 410 : 400).json({ error: err.message, code: err.code });
|
|
32614
|
+
return;
|
|
32615
|
+
}
|
|
31564
32616
|
if (err instanceof SessionWriterError) {
|
|
31565
32617
|
res.status(err.httpStatus).json({
|
|
31566
32618
|
error: err.message,
|
|
@@ -32132,7 +33184,7 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
32132
33184
|
app.get("/session/:id/events", async (req, res) => {
|
|
32133
33185
|
const sessionId = req.params["id"];
|
|
32134
33186
|
const diagnosticSessionId = boundedDiagnosticString(sessionId);
|
|
32135
|
-
const streamId =
|
|
33187
|
+
const streamId = randomUUID8();
|
|
32136
33188
|
const clientId = parseSseClientId(req.headers["x-qwen-client-id"]);
|
|
32137
33189
|
const connectReason = parseSseConnectReason(req.query["connectReason"]);
|
|
32138
33190
|
const previousStreamId = parsePreviousSseStreamId(
|
|
@@ -33154,6 +34206,19 @@ __name(registerA2uiActionRoutes, "registerA2uiActionRoutes");
|
|
|
33154
34206
|
init_esbuild_shims();
|
|
33155
34207
|
import * as path15 from "node:path";
|
|
33156
34208
|
var IDE_WORKSPACE_PATH_ENV_VAR = "QWEN_CODE_IDE_WORKSPACE_PATH";
|
|
34209
|
+
var NEW_FILE_MODE_ENV_VAR = "QWEN_SERVE_NEW_FILE_MODE";
|
|
34210
|
+
function parseNewFileModePolicy(env = process.env) {
|
|
34211
|
+
const raw = env[NEW_FILE_MODE_ENV_VAR];
|
|
34212
|
+
if (raw === void 0 || raw.trim() === "") return "owner";
|
|
34213
|
+
const normalized = raw.trim().toLowerCase();
|
|
34214
|
+
if (normalized === "system") return "system";
|
|
34215
|
+
if (normalized === "owner" || normalized === "0600") return "owner";
|
|
34216
|
+
writeStderrLine(
|
|
34217
|
+
`qwen serve: ignoring invalid ${NEW_FILE_MODE_ENV_VAR}=${raw} (expected 'system' or 'owner'); new files keep the 0600 default`
|
|
34218
|
+
);
|
|
34219
|
+
return "owner";
|
|
34220
|
+
}
|
|
34221
|
+
__name(parseNewFileModePolicy, "parseNewFileModePolicy");
|
|
33157
34222
|
function createDefaultFsAuditEmit() {
|
|
33158
34223
|
const WARN_EVERY = 100;
|
|
33159
34224
|
let droppedCount = 0;
|
|
@@ -33181,6 +34246,7 @@ function resolveBridgeFsFactory(input) {
|
|
|
33181
34246
|
emit: input.emit ?? createDefaultFsAuditEmit(),
|
|
33182
34247
|
pathLocks: input.pathLocks,
|
|
33183
34248
|
generationGuard: input.generationGuard,
|
|
34249
|
+
newFileMode: input.newFileMode ?? parseNewFileModePolicy(),
|
|
33184
34250
|
...input.customIgnoreFiles !== void 0 ? { customIgnoreFiles: input.customIgnoreFiles } : {}
|
|
33185
34251
|
});
|
|
33186
34252
|
}
|
|
@@ -33503,9 +34569,9 @@ __name(setupDeviceFlowRegistry, "setupDeviceFlowRegistry");
|
|
|
33503
34569
|
|
|
33504
34570
|
// packages/cli/src/serve/server/error-handlers.ts
|
|
33505
34571
|
init_esbuild_shims();
|
|
33506
|
-
var
|
|
34572
|
+
var import_express5 = __toESM(require_express(), 1);
|
|
33507
34573
|
function installJsonBodyParser(app) {
|
|
33508
|
-
app.use(
|
|
34574
|
+
app.use(import_express5.default.json({ limit: "10mb" }));
|
|
33509
34575
|
app.use((err, _req, res, next) => {
|
|
33510
34576
|
if (sendJsonBodyParserError(res, err)) return;
|
|
33511
34577
|
next(err);
|
|
@@ -38355,8 +39421,8 @@ __name(registerWorkspaceQualifiedSkillsRoutes, "registerWorkspaceQualifiedSkills
|
|
|
38355
39421
|
|
|
38356
39422
|
// packages/cli/src/serve/routes/channel-webhooks.ts
|
|
38357
39423
|
init_esbuild_shims();
|
|
38358
|
-
var
|
|
38359
|
-
import { createHash as
|
|
39424
|
+
var import_express6 = __toESM(require_express(), 1);
|
|
39425
|
+
import { createHash as createHash3, timingSafeEqual } from "node:crypto";
|
|
38360
39426
|
var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
38361
39427
|
"__proto__",
|
|
38362
39428
|
"constructor",
|
|
@@ -38404,7 +39470,7 @@ function registerChannelWebhookRoutes(app, deps) {
|
|
|
38404
39470
|
locals.channelWebhook = { channelName, source, sourceConfig };
|
|
38405
39471
|
next();
|
|
38406
39472
|
},
|
|
38407
|
-
|
|
39473
|
+
import_express6.default.json({ limit: "1mb" }),
|
|
38408
39474
|
async (req, res) => {
|
|
38409
39475
|
const locals = res.locals;
|
|
38410
39476
|
const webhook = locals.channelWebhook;
|
|
@@ -38518,9 +39584,9 @@ function matchesWebhookSecret(candidate, expected) {
|
|
|
38518
39584
|
if (typeof candidate !== "string") {
|
|
38519
39585
|
return false;
|
|
38520
39586
|
}
|
|
38521
|
-
const expectedDigest =
|
|
38522
|
-
const candidateDigest =
|
|
38523
|
-
return
|
|
39587
|
+
const expectedDigest = createHash3("sha256").update(expected).digest();
|
|
39588
|
+
const candidateDigest = createHash3("sha256").update(candidate).digest();
|
|
39589
|
+
return timingSafeEqual(expectedDigest, candidateDigest);
|
|
38524
39590
|
}
|
|
38525
39591
|
__name(matchesWebhookSecret, "matchesWebhookSecret");
|
|
38526
39592
|
function readPayload(body, res) {
|
|
@@ -38599,7 +39665,7 @@ init_esbuild_shims();
|
|
|
38599
39665
|
|
|
38600
39666
|
// packages/cli/src/serve/live/live-host-coordinator.ts
|
|
38601
39667
|
init_esbuild_shims();
|
|
38602
|
-
import { randomUUID as
|
|
39668
|
+
import { randomUUID as randomUUID9, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
38603
39669
|
var DEFAULT_HELLO_TIMEOUT_MS = 5e3;
|
|
38604
39670
|
var DEFAULT_HEARTBEAT_INTERVAL_MS = 5e3;
|
|
38605
39671
|
var DEFAULT_HEARTBEAT_TIMEOUT_MS = 15e3;
|
|
@@ -38776,7 +39842,7 @@ __name(projectStatusForHost, "projectStatusForHost");
|
|
|
38776
39842
|
var LiveHostCoordinator = class {
|
|
38777
39843
|
constructor(options) {
|
|
38778
39844
|
this.options = options;
|
|
38779
|
-
this.daemonInstanceNonce = options.daemonInstanceNonce ??
|
|
39845
|
+
this.daemonInstanceNonce = options.daemonInstanceNonce ?? randomUUID9();
|
|
38780
39846
|
this.handlers = options.handlers ?? {};
|
|
38781
39847
|
this.now = options.now ?? Date.now;
|
|
38782
39848
|
this.helloTimeoutMs = options.helloTimeoutMs ?? DEFAULT_HELLO_TIMEOUT_MS;
|
|
@@ -38845,7 +39911,7 @@ var LiveHostCoordinator = class {
|
|
|
38845
39911
|
attachHost(socket, daemonNonce) {
|
|
38846
39912
|
const expectedNonce = Buffer.from(this.daemonInstanceNonce);
|
|
38847
39913
|
const presentedNonce = Buffer.from(daemonNonce ?? "");
|
|
38848
|
-
if (expectedNonce.byteLength !== presentedNonce.byteLength || !
|
|
39914
|
+
if (expectedNonce.byteLength !== presentedNonce.byteLength || !timingSafeEqual2(expectedNonce, presentedNonce)) {
|
|
38849
39915
|
socket.close(4003, "Invalid daemon instance nonce.");
|
|
38850
39916
|
return;
|
|
38851
39917
|
}
|
|
@@ -38968,7 +40034,7 @@ var LiveHostCoordinator = class {
|
|
|
38968
40034
|
startCall(mode) {
|
|
38969
40035
|
const call = {
|
|
38970
40036
|
epoch: ++this.nextEpoch,
|
|
38971
|
-
callId:
|
|
40037
|
+
callId: randomUUID9(),
|
|
38972
40038
|
mode,
|
|
38973
40039
|
state: "starting",
|
|
38974
40040
|
pendingPermission: false,
|
|
@@ -39027,7 +40093,7 @@ var LiveHostCoordinator = class {
|
|
|
39027
40093
|
new Error("Qwen Live Host must be connected to change the shortcut.")
|
|
39028
40094
|
);
|
|
39029
40095
|
}
|
|
39030
|
-
const requestId =
|
|
40096
|
+
const requestId = randomUUID9();
|
|
39031
40097
|
return new Promise((resolve7, reject) => {
|
|
39032
40098
|
const timer = setTimeout(() => {
|
|
39033
40099
|
this.rejectPendingShortcut(
|
|
@@ -39117,7 +40183,7 @@ var LiveHostCoordinator = class {
|
|
|
39117
40183
|
)
|
|
39118
40184
|
);
|
|
39119
40185
|
}
|
|
39120
|
-
const requestId =
|
|
40186
|
+
const requestId = randomUUID9();
|
|
39121
40187
|
return new Promise((resolve7, reject) => {
|
|
39122
40188
|
const timer = setTimeout(() => {
|
|
39123
40189
|
this.pendingAppshots.delete(requestId);
|
|
@@ -39457,7 +40523,7 @@ var LiveHostCoordinator = class {
|
|
|
39457
40523
|
this.disconnectHost(lease, 4008, "Live Host heartbeat timed out.");
|
|
39458
40524
|
return;
|
|
39459
40525
|
}
|
|
39460
|
-
const pingId =
|
|
40526
|
+
const pingId = randomUUID9();
|
|
39461
40527
|
lease.pingId = pingId;
|
|
39462
40528
|
this.sendHost({ type: "host.ping", pingId });
|
|
39463
40529
|
}
|
|
@@ -39725,7 +40791,7 @@ init_esbuild_shims();
|
|
|
39725
40791
|
|
|
39726
40792
|
// packages/cli/src/serve/live/live-setup-controller.ts
|
|
39727
40793
|
init_esbuild_shims();
|
|
39728
|
-
import { randomUUID as
|
|
40794
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
39729
40795
|
|
|
39730
40796
|
// packages/cli/src/serve/live/provider-credentials.ts
|
|
39731
40797
|
init_esbuild_shims();
|
|
@@ -39823,7 +40889,7 @@ __name(resolveLiveProviderCredential, "resolveLiveProviderCredential");
|
|
|
39823
40889
|
|
|
39824
40890
|
// packages/cli/src/serve/live/qwen-realtime-session.ts
|
|
39825
40891
|
init_esbuild_shims();
|
|
39826
|
-
import { randomUUID as
|
|
40892
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
39827
40893
|
var QWEN_REALTIME_LIMITS = {
|
|
39828
40894
|
maxInputAudioFrameBytes: 64 * 1024,
|
|
39829
40895
|
maxOutputAudioFrameBytes: 256 * 1024,
|
|
@@ -40238,7 +41304,7 @@ function openQwenRealtimeSession(config, callbacks = {}, deps = {}) {
|
|
|
40238
41304
|
const sendJson = /* @__PURE__ */ __name((body) => {
|
|
40239
41305
|
if (terminal || closedByClient || ws.readyState !== ws.OPEN) return false;
|
|
40240
41306
|
try {
|
|
40241
|
-
ws.send(JSON.stringify({ event_id:
|
|
41307
|
+
ws.send(JSON.stringify({ event_id: randomUUID10(), ...body }));
|
|
40242
41308
|
return true;
|
|
40243
41309
|
} catch (error2) {
|
|
40244
41310
|
fail(
|
|
@@ -41601,7 +42667,7 @@ async function validateCredential(credential) {
|
|
|
41601
42667
|
apiKey: credential.apiKey,
|
|
41602
42668
|
model: credential.realtimeModel,
|
|
41603
42669
|
voice: credential.voice,
|
|
41604
|
-
callEpoch: `setup-${
|
|
42670
|
+
callEpoch: `setup-${randomUUID11()}`
|
|
41605
42671
|
});
|
|
41606
42672
|
session.close({ discardPendingInput: true });
|
|
41607
42673
|
}
|
|
@@ -41908,7 +42974,7 @@ __name(registerLiveSetupRoutes, "registerLiveSetupRoutes");
|
|
|
41908
42974
|
// packages/cli/src/serve/live/live-host-installer.ts
|
|
41909
42975
|
init_esbuild_shims();
|
|
41910
42976
|
import { execFile as execFile3 } from "node:child_process";
|
|
41911
|
-
import { createHash as
|
|
42977
|
+
import { createHash as createHash4, randomUUID as randomUUID12 } from "node:crypto";
|
|
41912
42978
|
import * as fs7 from "node:fs";
|
|
41913
42979
|
import * as fsp5 from "node:fs/promises";
|
|
41914
42980
|
import * as os2 from "node:os";
|
|
@@ -42083,7 +43149,7 @@ async function downloadAsset(asset, url, destination, onProgress, fetchImpl) {
|
|
|
42083
43149
|
});
|
|
42084
43150
|
throw new Error("Live Host download size does not match its manifest.");
|
|
42085
43151
|
}
|
|
42086
|
-
const hash =
|
|
43152
|
+
const hash = createHash4("sha256");
|
|
42087
43153
|
let received = 0;
|
|
42088
43154
|
const guard = new Transform({
|
|
42089
43155
|
transform(chunk, _encoding, callback) {
|
|
@@ -42139,8 +43205,8 @@ async function installLatestHost(currentArchitecture, onStatus) {
|
|
|
42139
43205
|
const archivePath = path16.join(temporaryDirectory, "Qwen-Live-Host.zip");
|
|
42140
43206
|
const extractedPath = path16.join(temporaryDirectory, "extracted");
|
|
42141
43207
|
const candidatePath = path16.join(extractedPath, LIVE_HOST_APP_NAME);
|
|
42142
|
-
const stagingPath = `/Applications/.Qwen Live Host.install-${
|
|
42143
|
-
const backupPath = `/Applications/.Qwen Live Host.backup-${
|
|
43208
|
+
const stagingPath = `/Applications/.Qwen Live Host.install-${randomUUID12()}.app`;
|
|
43209
|
+
const backupPath = `/Applications/.Qwen Live Host.backup-${randomUUID12()}.app`;
|
|
42144
43210
|
let movedExisting = false;
|
|
42145
43211
|
let installedCandidate = false;
|
|
42146
43212
|
try {
|
|
@@ -42288,7 +43354,7 @@ var LiveHostInstaller = class {
|
|
|
42288
43354
|
|
|
42289
43355
|
// packages/cli/src/serve/live/live-session-coordinator.ts
|
|
42290
43356
|
init_esbuild_shims();
|
|
42291
|
-
import { createHash as
|
|
43357
|
+
import { createHash as createHash5, randomUUID as randomUUID13 } from "node:crypto";
|
|
42292
43358
|
import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
42293
43359
|
import { join as join12 } from "node:path";
|
|
42294
43360
|
|
|
@@ -42663,7 +43729,7 @@ function openLiveAudioCapture(source, identifier) {
|
|
|
42663
43729
|
);
|
|
42664
43730
|
const stream = createWriteStream2(path19, { flags: "wx", mode: 384 });
|
|
42665
43731
|
stream.on("error", () => void 0);
|
|
42666
|
-
return { source, path: path19, stream, hash:
|
|
43732
|
+
return { source, path: path19, stream, hash: createHash5("sha256"), bytes: 0 };
|
|
42667
43733
|
} catch {
|
|
42668
43734
|
return void 0;
|
|
42669
43735
|
}
|
|
@@ -43018,7 +44084,7 @@ var LiveSessionCoordinator = class {
|
|
|
43018
44084
|
context.speechInProgress = true;
|
|
43019
44085
|
context.inputCommitPending = true;
|
|
43020
44086
|
context.inputAwaitingResponse = false;
|
|
43021
|
-
const partialItemId = itemId ?? `partial:${
|
|
44087
|
+
const partialItemId = itemId ?? `partial:${randomUUID13()}`;
|
|
43022
44088
|
context.activePartialInputItemId = partialItemId;
|
|
43023
44089
|
if (!context.partialInputTranscripts.has(partialItemId)) {
|
|
43024
44090
|
context.partialInputTranscripts.set(partialItemId, "");
|
|
@@ -43048,7 +44114,7 @@ var LiveSessionCoordinator = class {
|
|
|
43048
44114
|
}, "onInputCommitted"),
|
|
43049
44115
|
onInputTranscriptDelta: /* @__PURE__ */ __name(({ itemId, text }) => {
|
|
43050
44116
|
if (this.isCurrentSocket(context, generation)) {
|
|
43051
|
-
const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${
|
|
44117
|
+
const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${randomUUID13()}`;
|
|
43052
44118
|
context.activePartialInputItemId = partialItemId;
|
|
43053
44119
|
context.partialInputTranscripts.set(partialItemId, text);
|
|
43054
44120
|
this.options.host.setTranscript?.(context.epoch, text);
|
|
@@ -43058,7 +44124,7 @@ var LiveSessionCoordinator = class {
|
|
|
43058
44124
|
if (this.isCurrentSocket(context, generation)) {
|
|
43059
44125
|
context.speechInProgress = false;
|
|
43060
44126
|
context.inputCommitPending = false;
|
|
43061
|
-
const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${
|
|
44127
|
+
const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${randomUUID13()}`;
|
|
43062
44128
|
context.partialInputTranscripts.delete(completedItemId);
|
|
43063
44129
|
if (context.activePartialInputItemId === completedItemId) {
|
|
43064
44130
|
context.activePartialInputItemId = void 0;
|
|
@@ -43774,9 +44840,10 @@ var LiveSessionCoordinator = class {
|
|
|
43774
44840
|
if (!sessionClosed) return;
|
|
43775
44841
|
if (removeFreshTranscript) {
|
|
43776
44842
|
try {
|
|
43777
|
-
await new SessionService(
|
|
43778
|
-
|
|
43779
|
-
);
|
|
44843
|
+
const transcriptRemoved = await new SessionService(
|
|
44844
|
+
runtime.workspaceCwd
|
|
44845
|
+
).removeSession(session.sessionId);
|
|
44846
|
+
if (transcriptRemoved) bridge.markSessionCatalogChanged();
|
|
43780
44847
|
} catch {
|
|
43781
44848
|
}
|
|
43782
44849
|
}
|
|
@@ -43789,7 +44856,7 @@ var LiveSessionCoordinator = class {
|
|
|
43789
44856
|
const runtime = context.runtime;
|
|
43790
44857
|
if (!runtime) throw new Error("Conversation workspace is unavailable.");
|
|
43791
44858
|
const bridge = runtime.bridge;
|
|
43792
|
-
const promptId =
|
|
44859
|
+
const promptId = randomUUID13();
|
|
43793
44860
|
const lastEventId = bridge.getSessionLastEventId(locator.sessionId);
|
|
43794
44861
|
const turnAbort = new AbortController();
|
|
43795
44862
|
this.inFlightTurnAborts.add(turnAbort);
|
|
@@ -44106,7 +45173,7 @@ var LiveSessionCoordinator = class {
|
|
|
44106
45173
|
|
|
44107
45174
|
// packages/cli/src/serve/live/live-task-service.ts
|
|
44108
45175
|
init_esbuild_shims();
|
|
44109
|
-
import { randomUUID as
|
|
45176
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
44110
45177
|
var DEFAULT_LIST_LIMIT = 20;
|
|
44111
45178
|
var DEFAULT_READ_TURN_LIMIT = 3;
|
|
44112
45179
|
var DEFAULT_WAIT_TIMEOUT_MS = 12e4;
|
|
@@ -44823,7 +45890,7 @@ var LiveTaskService = class {
|
|
|
44823
45890
|
{ sessionId, prompt: [{ type: "text", text: prompt }] },
|
|
44824
45891
|
void 0,
|
|
44825
45892
|
{
|
|
44826
|
-
promptId:
|
|
45893
|
+
promptId: randomUUID14(),
|
|
44827
45894
|
onPromptAdmitted: /* @__PURE__ */ __name(() => {
|
|
44828
45895
|
admitted = true;
|
|
44829
45896
|
onAdmitted?.();
|
|
@@ -44889,10 +45956,11 @@ var LiveTaskService = class {
|
|
|
44889
45956
|
removed = false;
|
|
44890
45957
|
}
|
|
44891
45958
|
if (removed) {
|
|
44892
|
-
await runWithWorkspaceRuntimeStorage(
|
|
45959
|
+
const persistedRemoved = await runWithWorkspaceRuntimeStorage(
|
|
44893
45960
|
runtime,
|
|
44894
|
-
() => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() =>
|
|
45961
|
+
() => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() => false)
|
|
44895
45962
|
);
|
|
45963
|
+
if (persistedRemoved) runtime.bridge.markSessionCatalogChanged();
|
|
44896
45964
|
}
|
|
44897
45965
|
if (projectless && removed) {
|
|
44898
45966
|
await this.options.discardEmptyConversationDirectory(session.sessionId).catch(() => void 0);
|
|
@@ -45078,7 +46146,7 @@ var ConversationRuntimeManager = class {
|
|
|
45078
46146
|
|
|
45079
46147
|
// packages/cli/src/serve/conversations/conversation-runtime-ownership.ts
|
|
45080
46148
|
init_esbuild_shims();
|
|
45081
|
-
import { randomUUID as
|
|
46149
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
45082
46150
|
import { constants as fsConstants2 } from "node:fs";
|
|
45083
46151
|
import * as fs8 from "node:fs/promises";
|
|
45084
46152
|
import * as path17 from "node:path";
|
|
@@ -45214,16 +46282,20 @@ async function readOwnerRecord(ownerPath) {
|
|
|
45214
46282
|
process.platform === "win32" ? fsConstants2.O_RDONLY : fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW
|
|
45215
46283
|
);
|
|
45216
46284
|
} catch (error2) {
|
|
45217
|
-
|
|
46285
|
+
if (error2.code === "ELOOP") {
|
|
46286
|
+
throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
|
|
46287
|
+
}
|
|
46288
|
+
throw error2;
|
|
45218
46289
|
}
|
|
45219
46290
|
try {
|
|
45220
46291
|
const handleStat = await handle.stat();
|
|
45221
46292
|
if (!handleStat.isFile() || handleStat.nlink !== 1 || handleStat.dev !== pathStat.dev || handleStat.ino !== pathStat.ino || handleStat.size !== pathStat.size || process.platform !== "win32" && ((handleStat.mode & 511) !== 384 || typeof process.getuid === "function" && handleStat.uid !== process.getuid())) {
|
|
45222
46293
|
throw new UnsafeOwnershipStateError();
|
|
45223
46294
|
}
|
|
46295
|
+
const serialized = await handle.readFile("utf8");
|
|
45224
46296
|
let parsed;
|
|
45225
46297
|
try {
|
|
45226
|
-
parsed = JSON.parse(
|
|
46298
|
+
parsed = JSON.parse(serialized);
|
|
45227
46299
|
} catch (error2) {
|
|
45228
46300
|
throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
|
|
45229
46301
|
}
|
|
@@ -45349,7 +46421,7 @@ var FileConversationRuntimeOwnership = class {
|
|
|
45349
46421
|
await this.commitRecord(identity, void 0);
|
|
45350
46422
|
}
|
|
45351
46423
|
}, "commitOwner");
|
|
45352
|
-
const liveDiscovery = await import("./discovery-
|
|
46424
|
+
const liveDiscovery = await import("./discovery-X2NV535U.js");
|
|
45353
46425
|
const handoff = await liveDiscovery.handoffLiveDiscoveryOwner(
|
|
45354
46426
|
this.stableBaseDir,
|
|
45355
46427
|
this.current,
|
|
@@ -45466,7 +46538,7 @@ var FileConversationRuntimeOwnership = class {
|
|
|
45466
46538
|
async commitRecord(identity, expected) {
|
|
45467
46539
|
const temporaryPath = path17.join(
|
|
45468
46540
|
this.ownerDirectory,
|
|
45469
|
-
`.runtime-owner.${this.current.pid}.${
|
|
46541
|
+
`.runtime-owner.${this.current.pid}.${randomUUID15()}.tmp`
|
|
45470
46542
|
);
|
|
45471
46543
|
let handle;
|
|
45472
46544
|
let renamed = false;
|
|
@@ -45646,7 +46718,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
45646
46718
|
"createServeApp: runtime replacement/removal requires deps.getSessionBridges so session-id admission can inspect draining generations."
|
|
45647
46719
|
);
|
|
45648
46720
|
}
|
|
45649
|
-
const app = (0,
|
|
46721
|
+
const app = (0, import_express7.default)();
|
|
45650
46722
|
const serveAppLifecycle = installServeAppLifecycle(
|
|
45651
46723
|
app,
|
|
45652
46724
|
deps.serveAppLifecycle
|
|
@@ -46307,18 +47379,17 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
46307
47379
|
app.locals.stopWorkspaceGitState = () => workspaceGitState.dispose();
|
|
46308
47380
|
app.locals.stopWorkspaceGitStateForWorkspace = (workspaceCwd) => workspaceGitState.disposeWorkspace(workspaceCwd);
|
|
46309
47381
|
const workspaceQualifiedAcpEnabled = acpHttpEnabledAtBoot;
|
|
46310
|
-
|
|
46311
|
-
|
|
46312
|
-
|
|
46313
|
-
|
|
46314
|
-
|
|
46315
|
-
);
|
|
46316
|
-
}
|
|
46317
|
-
app.use(allowOriginCors(parsedAllowOrigins));
|
|
46318
|
-
} else {
|
|
46319
|
-
app.use(denyBrowserOriginCors);
|
|
47382
|
+
const parsedAllowOrigins = parseAllowOriginPatterns(opts.allowOrigins ?? []);
|
|
47383
|
+
if (parsedAllowOrigins.allowAny && !opts.token) {
|
|
47384
|
+
throw new Error(
|
|
47385
|
+
`Refusing to start with --allow-origin '*' but no bearer token configured. '*' admits any cross-origin browser to the API; without a token, any local page can drive the daemon. Set a token or list specific origins instead of '*'.`
|
|
47386
|
+
);
|
|
46320
47387
|
}
|
|
47388
|
+
const originAllowlist = new MutableOriginAllowlist(parsedAllowOrigins);
|
|
47389
|
+
app.use(allowOriginCors(originAllowlist));
|
|
46321
47390
|
app.use(hostAllowlist(opts.hostname, getPort));
|
|
47391
|
+
const credentials = new CredentialStore(opts.token);
|
|
47392
|
+
const authenticate = bearerAuth(credentials);
|
|
46322
47393
|
const rateLimiter = installRateLimiter(app, opts, daemonLog, {
|
|
46323
47394
|
mount: false,
|
|
46324
47395
|
workspaceQualifiedAcpEnabled
|
|
@@ -46330,6 +47401,13 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
46330
47401
|
getRateLimiter: /* @__PURE__ */ __name(() => rateLimiter, "getRateLimiter")
|
|
46331
47402
|
});
|
|
46332
47403
|
if (healthRoutes.exposeHealthPreAuth) {
|
|
47404
|
+
app.use("/health", (req, res, next) => {
|
|
47405
|
+
if (listenerIdentityOf(req).kind === "local-control") {
|
|
47406
|
+
authenticate(req, res, next);
|
|
47407
|
+
return;
|
|
47408
|
+
}
|
|
47409
|
+
next();
|
|
47410
|
+
});
|
|
46333
47411
|
healthRoutes.register(app);
|
|
46334
47412
|
}
|
|
46335
47413
|
installAccessLogMiddleware(app, daemonLog);
|
|
@@ -46373,7 +47451,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
46373
47451
|
daemonLog
|
|
46374
47452
|
});
|
|
46375
47453
|
}
|
|
46376
|
-
app.use(
|
|
47454
|
+
app.use(authenticate);
|
|
46377
47455
|
if (rateLimiter) {
|
|
46378
47456
|
app.use(rateLimiter.middleware);
|
|
46379
47457
|
}
|
|
@@ -47151,6 +48229,10 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
47151
48229
|
fsFactory: primaryRouteFileSystemFactory,
|
|
47152
48230
|
deviceFlowRegistry,
|
|
47153
48231
|
token: opts.token,
|
|
48232
|
+
// The WS upgrade bypasses Express middleware, so it needs the same
|
|
48233
|
+
// listener-scoped credentials the REST gate uses — otherwise the
|
|
48234
|
+
// `qwen-bearer.*` subprotocol would be a way around the scoping.
|
|
48235
|
+
credentials,
|
|
47154
48236
|
// Mirror the REST CORS allowlist onto the WS CSRF wall so an
|
|
47155
48237
|
// explicitly permitted origin (e.g. the extension's
|
|
47156
48238
|
// `chrome-extension://<id>`) can open the reverse tool channel.
|
|
@@ -47222,6 +48304,26 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
47222
48304
|
if (acpHandleRef.current) {
|
|
47223
48305
|
app.locals["acpHandle"] = acpHandleRef.current;
|
|
47224
48306
|
}
|
|
48307
|
+
const localControlService = new LocalControlService({
|
|
48308
|
+
app,
|
|
48309
|
+
credentials,
|
|
48310
|
+
originAllowlist,
|
|
48311
|
+
// Resolved through the ref on each call rather than captured so Local
|
|
48312
|
+
// Control cannot attach to a stale ACP mount.
|
|
48313
|
+
attachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.attachServer(server), "attachWebSocket"),
|
|
48314
|
+
detachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.detachServer(server), "detachWebSocket"),
|
|
48315
|
+
getPort,
|
|
48316
|
+
tlsPaths: opts.tlsCert && opts.tlsKey ? { cert: opts.tlsCert, key: opts.tlsKey } : void 0
|
|
48317
|
+
});
|
|
48318
|
+
app.locals["localControlService"] = localControlService;
|
|
48319
|
+
registerWorkspaceLocalControlRoutes(app, {
|
|
48320
|
+
service: localControlService,
|
|
48321
|
+
mutate,
|
|
48322
|
+
safeBody,
|
|
48323
|
+
isDaemonDraining: deps.isChannelControlDraining,
|
|
48324
|
+
webShellAvailable: Boolean(webShellDir),
|
|
48325
|
+
primaryBindHostname: opts.hostname
|
|
48326
|
+
});
|
|
47225
48327
|
if (webShellDir) {
|
|
47226
48328
|
mountWebShellSpaFallback(app, webShellDir, webShellFrameAncestors);
|
|
47227
48329
|
}
|