@qwen-code/qwen-code 0.19.5 → 0.19.6-nightly.20260705.015ee4248
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/dataviz/SKILL.md +50 -0
- package/bundled/dataviz/references/anti-patterns.md +12 -0
- package/bundled/dataviz/references/choosing-a-form.md +16 -0
- package/bundled/dataviz/references/palette.md +57 -0
- package/bundled/dataviz/scripts/validate_palette.js +328 -0
- package/bundled/loop/SKILL.md +1 -1
- package/bundled/qc-helper/docs/configuration/settings.md +14 -8
- package/bundled/qc-helper/docs/features/headless.md +2 -2
- package/bundled/qc-helper/docs/features/scheduled-tasks.md +4 -2
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/DESIGN.md +23 -0
- package/bundled/review/SKILL.md +65 -8
- package/chunks/{MaxSizedBox-5JV77KRA.js → MaxSizedBox-PRXTXIGC.js} +31 -30
- package/chunks/{StandaloneSessionPicker-MGUGB6PH.js → StandaloneSessionPicker-PV7BSC5D.js} +42 -41
- package/chunks/{acpAgent-4F36XM3X.js → acpAgent-F34HNAM3.js} +939 -424
- package/chunks/{agent-IWBUZI6A.js → agent-XSQDKLST.js} +26 -25
- package/chunks/{agent-headless-JUTICAYO.js → agent-headless-B63XCKWX.js} +26 -25
- package/chunks/{anthropicContentGenerator-WL3LJOUB.js → anthropicContentGenerator-INXXI4PW.js} +7 -7
- package/chunks/{artifact-tool-W76WC2JX.js → artifact-tool-H2TNPNP5.js} +16 -3
- package/chunks/{askUserQuestion-J3P6TH3V.js → askUserQuestion-MKL5ZTMC.js} +2 -2
- package/chunks/{bridge-DHZHQ4UV.js → bridge-NCZDJBRF.js} +34 -32
- package/chunks/{channel-worker-supervisor-EVPAYNZ5.js → channel-worker-supervisor-JUYQ5Z4R.js} +5 -5
- package/chunks/{chunk-AVQDCKNF.js → chunk-22MNNNXE.js} +4 -0
- package/chunks/chunk-3RW4AZJV.js +5063 -0
- package/chunks/chunk-3VJ7MT3N.js +111 -0
- package/chunks/{chunk-JKGCBO3O.js → chunk-3VRMGS3A.js} +4 -4
- package/chunks/{chunk-TN6RT6EJ.js → chunk-3WOJO5EJ.js} +16 -4
- package/chunks/{chunk-G7OQ3RFJ.js → chunk-42XGFRJS.js} +3 -3
- package/chunks/{chunk-MOUXUCXQ.js → chunk-4KJ2BPIT.js} +1 -1
- package/chunks/{chunk-PPFWEV7G.js → chunk-4RQIB5UZ.js} +62 -62
- package/chunks/{chunk-JJ6B3ZD3.js → chunk-544UZQBD.js} +3 -3
- package/chunks/{chunk-B236XPGF.js → chunk-5UDYETKK.js} +1 -1
- package/chunks/{chunk-7DMQRPC7.js → chunk-6BEOH4KK.js} +1 -1
- package/chunks/{chunk-CXBG27SF.js → chunk-6IAWPIQ6.js} +3 -2
- package/chunks/{chunk-MDBNFHIO.js → chunk-6MDY7FX3.js} +5 -5
- package/chunks/{chunk-RM3PGSGL.js → chunk-6SHO7WFF.js} +15 -2
- package/chunks/{chunk-YCU7QV7Q.js → chunk-73WGF3NW.js} +34 -1
- package/chunks/{chunk-T42ACHFI.js → chunk-7LTB54MK.js} +1 -1
- package/chunks/{chunk-SJVPSHXU.js → chunk-7U6J224Z.js} +132 -25
- package/chunks/{chunk-CSPSJU5R.js → chunk-7WLJPMWU.js} +17 -17
- package/chunks/{chunk-R6RI2HIC.js → chunk-ACD5DFUY.js} +41 -14
- package/chunks/{chunk-EWALXUAD.js → chunk-AGHU5VRK.js} +8 -0
- package/chunks/{chunk-GLPV75ES.js → chunk-AHNJGLFV.js} +2 -2
- package/chunks/{chunk-DRS2HTNT.js → chunk-AOAFX4PL.js} +5 -5
- package/chunks/{chunk-QHYITL6P.js → chunk-CK7IUFOB.js} +63 -22
- package/chunks/{chunk-RSBQS6M4.js → chunk-CODWJXQA.js} +1 -1
- package/chunks/{chunk-LWGLBVWA.js → chunk-CSOTA7KX.js} +1 -1
- package/chunks/{chunk-UJT42DB6.js → chunk-DFH4T5IQ.js} +6 -6
- package/chunks/{chunk-DX3TKXNT.js → chunk-DJACOX4C.js} +2 -2
- package/chunks/{chunk-KKQWC6WS.js → chunk-DNV4FSN5.js} +1 -1
- package/chunks/{chunk-YPCPZSZB.js → chunk-DT3B47QP.js} +1 -1
- package/chunks/{chunk-NIOPRZNN.js → chunk-E7KNELIZ.js} +1 -1
- package/chunks/{chunk-DG573EOO.js → chunk-FEJ2FZ3U.js} +1 -1
- package/chunks/{chunk-M5ITDKSM.js → chunk-FHGQFG2K.js} +1 -1
- package/chunks/{chunk-HISPEX42.js → chunk-FSXFNDTI.js} +7 -7
- package/chunks/{chunk-LHMZCIKL.js → chunk-FUW7YGJU.js} +3 -1
- package/chunks/{chunk-Y4UQT3PM.js → chunk-FV5SBNNC.js} +1 -1
- package/chunks/{chunk-YTFBURQD.js → chunk-GB6HDZIK.js} +10 -2
- package/chunks/{chunk-D5KISTLW.js → chunk-H6EMK6QK.js} +1 -1
- package/chunks/{chunk-2Z43HUXT.js → chunk-HLKG6CZN.js} +3 -2
- package/chunks/{chunk-VXGPYF7U.js → chunk-IFEWJXFS.js} +1 -1
- package/chunks/{chunk-TENOUWY2.js → chunk-IJRL2S3D.js} +3 -3
- package/chunks/{chunk-OQHLUA2Y.js → chunk-IL6ZEDZ2.js} +4 -4
- package/chunks/{chunk-2CAII5HD.js → chunk-J7XUJALJ.js} +1 -1
- package/chunks/chunk-JFFOH2XO.js +2472 -0
- package/chunks/{chunk-NNEJEBCF.js → chunk-K3FZXSTO.js} +95 -107
- package/chunks/{chunk-NDY7OENU.js → chunk-KB4ICCA5.js} +3 -3
- package/chunks/{chunk-MNOXKSM2.js → chunk-LFFF2SPV.js} +3 -3
- package/chunks/{chunk-J3ERRYYI.js → chunk-LTMDKOZC.js} +2 -2
- package/chunks/{chunk-R3UWLLRQ.js → chunk-M7AGQP5D.js} +1 -1
- package/chunks/{chunk-CBJE2PLG.js → chunk-MLB5AB2I.js} +4 -4
- package/chunks/{chunk-YHTNWGRR.js → chunk-MZ7BABX3.js} +1 -1
- package/chunks/{chunk-SJBIFVD2.js → chunk-NFE3DQ4R.js} +7 -3
- package/chunks/{chunk-BC4R5C5R.js → chunk-NLD2WKE3.js} +55 -12
- package/chunks/{chunk-ALX6BUYW.js → chunk-NUGPZXAZ.js} +35 -1
- package/chunks/{chunk-NSSVORTQ.js → chunk-NYKWPUAE.js} +17 -13
- package/chunks/{chunk-K4I4STSL.js → chunk-OGEJMKN5.js} +2 -2
- package/chunks/{chunk-HTWHAN44.js → chunk-PC4ZXHU2.js} +1 -1
- package/chunks/{chunk-2YH27UNF.js → chunk-QLBBV7C6.js} +1 -1
- package/chunks/chunk-QT7XKZT7.js +293 -0
- package/chunks/{chunk-NPQWQYU6.js → chunk-QYNNN7BK.js} +1 -1
- package/chunks/chunk-R4N3OALZ.js +5631 -0
- package/chunks/{chunk-G4M7FPNY.js → chunk-RB5GAQR6.js} +2 -2
- package/chunks/{chunk-SBMHB6N5.js → chunk-RPHMD5UC.js} +15 -15
- package/chunks/{chunk-CHY5C5T4.js → chunk-SJ2CTIYH.js} +185 -88
- package/chunks/chunk-SLQXGMYY.js +949 -0
- package/chunks/{chunk-BZHLWC6T.js → chunk-SUAKHHK7.js} +2 -2
- package/chunks/{chunk-IMAMNLY6.js → chunk-SWV4CVYG.js} +158 -3
- package/chunks/{chunk-XKSCTXPK.js → chunk-TDGF35EN.js} +4 -3
- package/chunks/{chunk-TOAUDIS7.js → chunk-TLWA7TPR.js} +6 -2
- package/chunks/{chunk-WALEWZ44.js → chunk-UVHL5TCO.js} +1 -1
- package/chunks/{chunk-ZISMVA6U.js → chunk-VDMM5LVR.js} +1566 -37
- package/chunks/{chunk-BPFJQGY7.js → chunk-VEB3NYSO.js} +164 -5
- package/chunks/{chunk-L7OJ3ZO3.js → chunk-VZ7HY3YU.js} +1 -1
- package/chunks/{chunk-6KPZJJ6U.js → chunk-W4I6PLEG.js} +131 -38
- package/chunks/{chunk-QOMAHFYI.js → chunk-W7EEOR7D.js} +3 -3
- package/chunks/{chunk-6QVQZAW6.js → chunk-WKP5QZOP.js} +1 -1
- package/chunks/{chunk-YXK4GPYO.js → chunk-WMPVYQ4P.js} +30 -1
- package/chunks/{chunk-DM4E337C.js → chunk-WNTS5A2R.js} +5 -5
- package/chunks/{chunk-6QTCOQX7.js → chunk-WOG7QWIT.js} +3086 -2635
- package/chunks/{chunk-UY2TCIZS.js → chunk-X265R5C6.js} +3 -3
- package/chunks/{chunk-LKWAVAB5.js → chunk-X2XNQQJI.js} +2 -2
- package/chunks/{chunk-MTNTVOJR.js → chunk-X3YGAX7V.js} +6 -3
- package/chunks/{chunk-EROWZQN7.js → chunk-XD3OLPII.js} +6 -6
- package/chunks/{chunk-RNGAT2Y2.js → chunk-YYL6HROQ.js} +1 -1
- package/chunks/{chunk-XKZXGIRM.js → chunk-YZ2LNTHO.js} +2 -2
- package/chunks/{chunk-Z7XNVNPM.js → chunk-YZ5ANQMR.js} +3 -3
- package/chunks/{chunk-4MCC4XHH.js → chunk-Z7EYROOJ.js} +3568 -5508
- package/chunks/{chunk-5B2WNM6V.js → chunk-ZI4MGBB5.js} +1 -1
- package/chunks/{chunk-WZ724G6K.js → chunk-ZPGE42V7.js} +6 -6
- package/chunks/{computer-use-ON3JQUHW.js → computer-use-5I2UHVNY.js} +26 -25
- package/chunks/{contextCommand-OGCG7W6N.js → contextCommand-3NWY7AJG.js} +28 -27
- package/chunks/{cron-create-6YTCOX6P.js → cron-create-O6ZHD3JN.js} +22 -7
- package/chunks/{cron-delete-E3NIFSUK.js → cron-delete-BFD5B2XX.js} +4 -4
- package/chunks/{cron-list-Q64MNQNE.js → cron-list-KI6FV4KN.js} +4 -4
- package/chunks/{daemon-EEB2RYOL.js → daemon-DRUMLVFP.js} +140 -0
- package/chunks/daemon-status-provider-A2DK3ZTO.js +74 -0
- package/chunks/{dist-AP5V4WYU.js → dist-AAO65DPC.js} +2 -2
- package/chunks/{dist-X4ZDE726.js → dist-ABQ7VWRR.js} +3 -3
- package/chunks/{dist-SNXOUPYS.js → dist-AW5ZYMUI.js} +2 -2
- package/chunks/{dist-Z57Q4YF5.js → dist-DN6M6TJ5.js} +525 -95
- package/chunks/{dist-IZP2VV4C.js → dist-JPSVN367.js} +2 -2
- package/chunks/{earlyInputCapture-DAFHSGVW.js → earlyInputCapture-5TMSSPQ5.js} +27 -26
- package/chunks/{edit-3QFNCSZH.js → edit-V4ITLSUD.js} +27 -26
- package/chunks/{en-M4EBUBNU.js → en-AXARKOWO.js} +2 -0
- package/chunks/{enter-worktree-62EQQMLD.js → enter-worktree-7ULPRMTJ.js} +26 -25
- package/chunks/{enterPlanMode-VUQSE4EG.js → enterPlanMode-YSHMLHJZ.js} +26 -25
- package/chunks/{errors-PW75PZXE.js → errors-TCUTD7NF.js} +28 -27
- package/chunks/{exit-worktree-VVNH7OVY.js → exit-worktree-JZDCKR6A.js} +26 -25
- package/chunks/{exitPlanMode-RUYRCYZW.js → exitPlanMode-GOQBN6SG.js} +26 -25
- package/chunks/{fast-path-TFRJRTTR.js → fast-path-F2HGAKO2.js} +3 -3
- package/chunks/{fast-path-settings-UQLRFDQP.js → fast-path-settings-RCRXH2JG.js} +2 -2
- package/chunks/{gemini-XW7ZDUVR.js → gemini-3M7ECKNW.js} +86 -80
- package/chunks/{geminiContentGenerator-MZDVHVZH.js → geminiContentGenerator-5EG3QEJM.js} +4 -4
- package/chunks/{glob-WAY2PUWA.js → glob-2DBDTLR4.js} +54 -29
- package/chunks/{grep-W6CBKSYC.js → grep-R27DLGWT.js} +26 -25
- package/chunks/{initializer-HK2XE6P2.js → initializer-OXB6BJZU.js} +32 -31
- package/chunks/{keychain-token-storage-GPAKRDKQ.js → keychain-token-storage-UJV5XP4Z.js} +2 -2
- package/chunks/{list-RVLIIKKL.js → list-HLCOEOSF.js} +33 -32
- package/chunks/{loadedSettingsAdapter-C63OUYZC.js → loadedSettingsAdapter-JHTVH3YO.js} +31 -30
- package/chunks/{loop-wakeup-G2EHBRGR.js → loop-wakeup-CUVIY2JY.js} +5 -5
- package/chunks/{ls-IDHUVSAG.js → ls-L654WOAT.js} +4 -4
- package/chunks/{lsp-FSRYXGFT.js → lsp-M35KE54Y.js} +2 -2
- package/chunks/mcp-2JWEFAIN.js +67 -0
- package/chunks/{monitor-FOG36ABM.js → monitor-5QKFZFDX.js} +26 -25
- package/chunks/nonInteractiveCli-W5W5PIHI.js +112 -0
- package/chunks/{notebook-edit-GC6NXRCX.js → notebook-edit-XAFBWORI.js} +27 -26
- package/chunks/{openaiContentGenerator-EXR3ZL3Z.js → openaiContentGenerator-NULJROYV.js} +13 -12
- package/chunks/{pidfile-FNZM2DDH.js → pidfile-3LT7PZSW.js} +27 -26
- package/chunks/{qwenContentGenerator-A7B6J4U7.js → qwenContentGenerator-KLSURVNH.js} +28 -27
- package/chunks/{qwenOAuth2-LWLA6MQG.js → qwenOAuth2-ZV7YLMND.js} +5 -5
- package/chunks/{read-file-6JL4ULMY.js → read-file-HDAM3RHJ.js} +8 -8
- package/chunks/{read-mcp-resource-PIJF24RO.js → read-mcp-resource-CNQHBSJM.js} +2 -2
- package/chunks/record-artifact-PP3LKHTS.js +343 -0
- package/chunks/{ripGrep-DIUGLJE5.js → ripGrep-W36NLR7M.js} +26 -25
- package/chunks/{run-qwen-serve-CME3AKM4.js → run-qwen-serve-IMI2CQB5.js} +72 -28
- package/chunks/{scheduler-L7F6GDDT.js → scheduler-I5NKE5UJ.js} +26 -25
- package/chunks/{send-message-33PYFMCT.js → send-message-OA6MV4EU.js} +3 -3
- package/chunks/{serve-SRCBOJGP.js → serve-JMHMOYBO.js} +33 -32
- package/chunks/{server-QSQ45QFR.js → server-QIYIN34N.js} +1358 -492
- package/chunks/{session-5DG6NXHZ.js → session-BLL6HB35.js} +68 -65
- package/chunks/{settings-3EEQI4MN.js → settings-ABECXCTY.js} +30 -29
- package/chunks/{shell-B7FNYF5S.js → shell-A2TQI3U4.js} +26 -25
- package/chunks/{skill-AAOGHD5O.js → skill-4GTWZZWR.js} +10 -10
- package/chunks/{spawnChannel-3CBN3ZLK.js → spawnChannel-DFUVGP53.js} +30 -29
- package/chunks/{src-T5A7P7FS.js → src-ZORBMUM7.js} +77 -43
- package/chunks/{startInteractiveUI-2FGEQ6AS.js → startInteractiveUI-FH5MVXUE.js} +449 -175
- package/chunks/{syntheticOutput-YOSWIHDJ.js → syntheticOutput-F7LSDCAR.js} +3 -3
- package/chunks/{task-create-NHS2NGB3.js → task-create-RPFZNB4B.js} +7 -7
- package/chunks/{task-list-5UIB564R.js → task-list-TGGJX7EA.js} +5 -5
- package/chunks/{task-stop-HGXZ2VZ3.js → task-stop-W7NGTMYQ.js} +2 -2
- package/chunks/{task-update-IYYWUILG.js → task-update-5WUG5MVQ.js} +7 -7
- package/chunks/{team-create-KDF6W6PV.js → team-create-F76QOR6H.js} +26 -25
- package/chunks/{team-delete-FEKJCU4P.js → team-delete-UHQQ2QQX.js} +5 -5
- package/chunks/{team-plan-approval-PSFKQX7M.js → team-plan-approval-OKM7YZC2.js} +26 -25
- package/chunks/{theme-manager-5XOA2AO7.js → theme-manager-6R7EVWHW.js} +27 -26
- package/chunks/{todoWrite-TKMVZ2HT.js → todoWrite-C4ZAMSR3.js} +4 -4
- package/chunks/{tool-search-LFRILZXC.js → tool-search-UWXDKI7D.js} +9 -9
- package/chunks/{trustedFolders-7HQY6T6X.js → trustedFolders-DHASVVUP.js} +27 -26
- package/chunks/{validateNonInterActiveAuth-UC27B7BA.js → validateNonInterActiveAuth-56J7MOOP.js} +62 -59
- package/chunks/version-NE2I4PBN.js +10 -0
- package/chunks/{web-fetch-J4PIW36Q.js → web-fetch-UYGMOHW4.js} +5 -5
- package/chunks/{workflow-KUTESS6L.js → workflow-HGF3URV3.js} +35 -27
- package/chunks/{workspace-providers-status-LJT5AQDS.js → workspace-providers-status-KXB2OZFQ.js} +33 -32
- package/chunks/{workspace-service-YOBYVDXH.js → workspace-service-NSTI55BC.js} +39 -38
- package/chunks/workspace-skills-status-X5S6JGQZ.js +69 -0
- package/chunks/{write-file-FJYBZUHP.js → write-file-HVKT5VTX.js} +27 -26
- package/chunks/yargs-B64EYTCF.js +10 -0
- package/chunks/{zh-SLZNSSZB.js → zh-RS3HZHFH.js} +2 -0
- package/chunks/{zh-TW-P53C2SL5.js → zh-TW-L5GRQ4S4.js} +2 -0
- package/cli-entry.js +81 -8
- package/cli.js +348 -55
- package/locales/en.js +2 -0
- package/locales/zh-TW.js +2 -0
- package/locales/zh.js +2 -0
- package/node_modules/@qwen-code/audio-capture/package.json +1 -1
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-D_rAuMDd.js → arc-Csx4m4N0.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-DUCzbHVo.js → architectureDiagram-3BPJPVTR-BEa0vCM7.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BEEBt1LL.js → blockDiagram-GPEHLZMM-BPzbKnn3.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-5ZJ_DeFL.js → c4Diagram-AAUBKEIU-B8YO71yP.js} +1 -1
- package/web-shell/assets/channel-QU1XUuVe.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-Cfw7EiLn.js → chunk-2J33WTMH-32XhwSHt.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-FGuZNCZY.js → chunk-4BX2VUAB-Bmoyo6PS.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-CaBwYPBF.js → chunk-55IACEB6-TwH6PFhs.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-BlR04OFz.js → chunk-727SXJPM-RI_IVUtZ.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-D3_mYJH5.js → chunk-AQP2D5EJ-DH6GIAZD.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-7D4q4SbB.js → chunk-FMBD7UC4-DeD3k3D5.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-BjX_Iwmr.js → chunk-ND2GUHAM-BLPb8nv3.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-C3Hz_ZQh.js → chunk-QZHKN3VN-PZpyglW1.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-fv1EWO-L.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-fv1EWO-L.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-Ax4UycaT.js → cose-bilkent-S5V4N54A-Jsd0yKfz.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-C6hmPtGt.js → dagre-BM42HDAG-B-zADciZ.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-tXZnxjmw.js → diagram-2AECGRRQ-Cn6GDxoo.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-99dwIzQG.js → diagram-5GNKFQAL-udLgyJxO.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-Bqhn0-2s.js → diagram-KO2AKTUF-EcLpfzy3.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DzThVSvo.js → diagram-LMA3HP47-D-YFbYsJ.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-DPE8vjln.js → diagram-OG6HWLK6-C8oRUATa.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-KzUKgQCV.js → erDiagram-TEJ5UH35-DPH5nStc.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-DBN-DXw5.js → flowDiagram-I6XJVG4X-CSOTwkAt.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-DuBsP9u8.js → ganttDiagram-6RSMTGT7-D0L988t0.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BjWHMyKR.js → gitGraphDiagram-PVQCEYII-B9Oo7gxS.js} +1 -1
- package/web-shell/assets/index-BYZZL5N7.css +5 -0
- package/web-shell/assets/index-C_oTyz0s.js +753 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-BVux0vP6.js → infoDiagram-5YYISTIA-Ddj4YN2P.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-2qzw7f--.js → ishikawaDiagram-YF4QCWOH-CBjafcl7.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-Dnl65sxL.js → journeyDiagram-JHISSGLW-Bn3XD99u.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-BElSQYtY.js → kanban-definition-UN3LZRKU-D7PBPJmE.js} +1 -1
- package/web-shell/assets/{linear-BjoycSSY.js → linear-Bmfo22rZ.js} +1 -1
- package/web-shell/assets/{mermaid.core-xe6bvMRz.js → mermaid.core-xRkAI-EI.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-D8DQgI4U.js → mindmap-definition-RKZ34NQL-B30zRinm.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-Dwh7Gp7c.js → pieDiagram-4H26LBE5-DblnKR9Z.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BXKNBln2.js → quadrantDiagram-W4KKPZXB-COkHFKjF.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BzaC3cIA.js → requirementDiagram-4Y6WPE33-DDU3MMyn.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-DP2t7eZk.js → sankeyDiagram-5OEKKPKP-Dt4lqEYv.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-XlFiWEYv.js → sequenceDiagram-3UESZ5HK-BRzby5gN.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CupgUMJO.js → stateDiagram-AJRCARHV-CylzByc3.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BKWZIKkM.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-DstuGywa.js → timeline-definition-PNZ67QCA-BSzaNx6w.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-CnbNp6zu.js → vennDiagram-CIIHVFJN-BbzeKzCo.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-DnvoHq6R.js → wardley-L42UT6IY-BRJwCgE_.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-Cz0xHEWB.js → wardleyDiagram-YWT4CUSO-BmAs0mJ-.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-p36gfo88.js → xychartDiagram-2RQKCTM6-DqywSqVW.js} +1 -1
- package/web-shell/index.html +2 -2
- package/bundled/loop/SKILL.test.ts +0 -119
- package/bundled/loop/autonomous-loop.test.ts +0 -59
- package/bundled/loop/loop-task-file.test.ts +0 -1064
- package/bundled/loop/loop-tick-resolver.test.ts +0 -906
- package/chunks/chunk-EJ7BN3EN.js +0 -11396
- package/chunks/chunk-L7QPM2YD.js +0 -481
- package/chunks/daemon-status-provider-P72STMLB.js +0 -72
- package/chunks/nonInteractiveCli-6BYQSJTB.js +0 -109
- package/chunks/workspace-skills-status-ONEPXJV6.js +0 -62
- package/web-shell/assets/channel-B5ynH0q8.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CK3ibywp.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CK3ibywp.js +0 -1
- package/web-shell/assets/index-9qfvU0_r.css +0 -5
- package/web-shell/assets/index-CWzDaQT5.js +0 -717
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-By3E4QwN.js +0 -1
- package/chunks/{chunk-UFC57OYT.js → chunk-VRDMOSQS.js} +54 -54
|
@@ -24,8 +24,12 @@ import {
|
|
|
24
24
|
isNotCurrentlyGeneratingCancelError
|
|
25
25
|
} from "./chunk-T22H4V4R.js";
|
|
26
26
|
import {
|
|
27
|
+
LOAD_REPLAY_BULK_MODE,
|
|
28
|
+
LOAD_REPLAY_META_KEY,
|
|
29
|
+
LOAD_REPLAY_MODE_META_KEY,
|
|
30
|
+
LOAD_REPLAY_VERSION,
|
|
27
31
|
MID_TURN_QUEUE_DRAIN_METHOD
|
|
28
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-AGHU5VRK.js";
|
|
29
33
|
import {
|
|
30
34
|
canonicalizeWorkspace
|
|
31
35
|
} from "./chunk-SEZC2725.js";
|
|
@@ -33,10 +37,15 @@ import {
|
|
|
33
37
|
DEFAULT_RING_SIZE,
|
|
34
38
|
EVENT_SCHEMA_VERSION,
|
|
35
39
|
EventBus
|
|
36
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-NUGPZXAZ.js";
|
|
41
|
+
import {
|
|
42
|
+
ClientSideConnection,
|
|
43
|
+
PROTOCOL_VERSION,
|
|
44
|
+
RequestError
|
|
45
|
+
} from "./chunk-VRDMOSQS.js";
|
|
37
46
|
import {
|
|
38
47
|
defaultSpawnChannelFactory
|
|
39
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-XD3OLPII.js";
|
|
40
49
|
import {
|
|
41
50
|
BridgeChannelClosedError,
|
|
42
51
|
BridgeTimeoutError,
|
|
@@ -45,20 +54,15 @@ import {
|
|
|
45
54
|
STATUS_SCHEMA_VERSION,
|
|
46
55
|
createIdleWorkspaceExtensionsStatus,
|
|
47
56
|
createIdleWorkspaceHooksStatus
|
|
48
|
-
} from "./chunk-
|
|
49
|
-
import {
|
|
50
|
-
ClientSideConnection,
|
|
51
|
-
PROTOCOL_VERSION,
|
|
52
|
-
RequestError
|
|
53
|
-
} from "./chunk-UFC57OYT.js";
|
|
57
|
+
} from "./chunk-FUW7YGJU.js";
|
|
54
58
|
import {
|
|
55
59
|
ShellExecutionService,
|
|
56
60
|
TrustGateError
|
|
57
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-WOG7QWIT.js";
|
|
58
62
|
import {
|
|
59
63
|
DAEMON_TRACEPARENT_META_KEY,
|
|
60
64
|
DAEMON_TRACESTATE_META_KEY
|
|
61
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-SJ2CTIYH.js";
|
|
62
66
|
import {
|
|
63
67
|
init_esbuild_shims
|
|
64
68
|
} from "./chunk-A4BMJM77.js";
|
|
@@ -69,7 +73,7 @@ import {
|
|
|
69
73
|
// packages/acp-bridge/src/bridge.ts
|
|
70
74
|
init_esbuild_shims();
|
|
71
75
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
72
|
-
import * as
|
|
76
|
+
import * as path3 from "node:path";
|
|
73
77
|
|
|
74
78
|
// packages/acp-bridge/src/compactionEngine.ts
|
|
75
79
|
init_esbuild_shims();
|
|
@@ -943,8 +947,8 @@ var MultiClientPermissionMediator = class {
|
|
|
943
947
|
}
|
|
944
948
|
this.resolved.set(record.requestId, record);
|
|
945
949
|
while (this.resolvedOrder.length > MAX_RESOLVED_PERMISSION_RECORDS) {
|
|
946
|
-
const
|
|
947
|
-
if (
|
|
950
|
+
const oldest2 = this.resolvedOrder.shift();
|
|
951
|
+
if (oldest2 !== void 0) this.resolved.delete(oldest2);
|
|
948
952
|
}
|
|
949
953
|
}
|
|
950
954
|
safeEmit(sessionId, event) {
|
|
@@ -1035,10 +1039,108 @@ var MultiClientPermissionMediator = class {
|
|
|
1035
1039
|
};
|
|
1036
1040
|
|
|
1037
1041
|
// packages/acp-bridge/src/bridgeClient.ts
|
|
1042
|
+
var PUBLISH_ARTIFACT_TOOL_NAME = "artifact";
|
|
1038
1043
|
function isFsErrorShape(err) {
|
|
1039
1044
|
return err instanceof Error && err.name === "FsError" && typeof err.kind === "string";
|
|
1040
1045
|
}
|
|
1041
1046
|
__name(isFsErrorShape, "isFsErrorShape");
|
|
1047
|
+
function isRecord(value) {
|
|
1048
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1049
|
+
}
|
|
1050
|
+
__name(isRecord, "isRecord");
|
|
1051
|
+
function artifactPayloadFields(artifact) {
|
|
1052
|
+
return {
|
|
1053
|
+
title: artifact["title"],
|
|
1054
|
+
kind: artifact["kind"],
|
|
1055
|
+
storage: artifact["storage"],
|
|
1056
|
+
description: artifact["description"],
|
|
1057
|
+
workspacePath: artifact["workspacePath"],
|
|
1058
|
+
managedId: artifact["managedId"],
|
|
1059
|
+
url: artifact["url"],
|
|
1060
|
+
mimeType: artifact["mimeType"],
|
|
1061
|
+
sizeBytes: artifact["sizeBytes"],
|
|
1062
|
+
metadata: artifact["metadata"]
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
__name(artifactPayloadFields, "artifactPayloadFields");
|
|
1066
|
+
function extractCappedArtifactInputs(rawArtifacts, limit, sessionId, source, toInput) {
|
|
1067
|
+
const artifacts = [];
|
|
1068
|
+
for (let index = 0; index < rawArtifacts.length; index++) {
|
|
1069
|
+
const artifact = rawArtifacts[index];
|
|
1070
|
+
if (!isRecord(artifact)) {
|
|
1071
|
+
writeStderrLine(
|
|
1072
|
+
`[artifacts] session=${sessionId} action=dropped reason=malformed source=${source} index=${index}`
|
|
1073
|
+
);
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
if (artifacts.length >= limit) {
|
|
1077
|
+
writeStderrLine(
|
|
1078
|
+
`[artifacts] session=${sessionId} action=dropped reason="artifact batch limit exceeded" source=${source} dropped=${rawArtifacts.length - index}`
|
|
1079
|
+
);
|
|
1080
|
+
break;
|
|
1081
|
+
}
|
|
1082
|
+
artifacts.push(toInput(artifact));
|
|
1083
|
+
}
|
|
1084
|
+
return artifacts;
|
|
1085
|
+
}
|
|
1086
|
+
__name(extractCappedArtifactInputs, "extractCappedArtifactInputs");
|
|
1087
|
+
function artifactIngestionErrorReason(error) {
|
|
1088
|
+
if (!(error instanceof Error)) {
|
|
1089
|
+
return String(error);
|
|
1090
|
+
}
|
|
1091
|
+
return {
|
|
1092
|
+
name: error.name,
|
|
1093
|
+
message: error.message,
|
|
1094
|
+
stack: error.stack?.split("\n").slice(0, 4).join("\n")
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
__name(artifactIngestionErrorReason, "artifactIngestionErrorReason");
|
|
1098
|
+
function extractSessionUpdateArtifacts(params, updateMeta, limit, sessionId) {
|
|
1099
|
+
const rawArtifacts = updateMeta?.["artifacts"];
|
|
1100
|
+
if (!Array.isArray(rawArtifacts)) {
|
|
1101
|
+
return [];
|
|
1102
|
+
}
|
|
1103
|
+
const update = params.update;
|
|
1104
|
+
if (update.sessionUpdate !== "tool_call_update" || update.status !== "completed" && update.status !== "failed" && update.status !== "cancelled") {
|
|
1105
|
+
return [];
|
|
1106
|
+
}
|
|
1107
|
+
const toolCallId = typeof update.toolCallId === "string" ? update.toolCallId : void 0;
|
|
1108
|
+
const toolName = typeof updateMeta?.["toolName"] === "string" ? updateMeta["toolName"] : void 0;
|
|
1109
|
+
return extractCappedArtifactInputs(
|
|
1110
|
+
rawArtifacts,
|
|
1111
|
+
limit,
|
|
1112
|
+
sessionId,
|
|
1113
|
+
"tool",
|
|
1114
|
+
(artifact) => ({
|
|
1115
|
+
...artifactPayloadFields(artifact),
|
|
1116
|
+
source: "tool",
|
|
1117
|
+
toolCallId,
|
|
1118
|
+
toolName
|
|
1119
|
+
})
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
__name(extractSessionUpdateArtifacts, "extractSessionUpdateArtifacts");
|
|
1123
|
+
function sanitizeSessionUpdateArtifacts(params, updateMeta) {
|
|
1124
|
+
if (!Array.isArray(updateMeta?.["artifacts"])) {
|
|
1125
|
+
return params;
|
|
1126
|
+
}
|
|
1127
|
+
const sanitizedMeta = { ...updateMeta };
|
|
1128
|
+
delete sanitizedMeta["artifacts"];
|
|
1129
|
+
const update = {
|
|
1130
|
+
...params.update,
|
|
1131
|
+
_meta: sanitizedMeta
|
|
1132
|
+
};
|
|
1133
|
+
return {
|
|
1134
|
+
...params,
|
|
1135
|
+
update
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
__name(sanitizeSessionUpdateArtifacts, "sanitizeSessionUpdateArtifacts");
|
|
1139
|
+
function isTrustedArtifactToolUpdate(params, updateMeta) {
|
|
1140
|
+
const update = params.update;
|
|
1141
|
+
return update.sessionUpdate === "tool_call_update" && update.status === "completed" && updateMeta?.["toolName"] === PUBLISH_ARTIFACT_TOOL_NAME;
|
|
1142
|
+
}
|
|
1143
|
+
__name(isTrustedArtifactToolUpdate, "isTrustedArtifactToolUpdate");
|
|
1042
1144
|
function preserveFsErrorOverAcp(err) {
|
|
1043
1145
|
if (isFsErrorShape(err)) {
|
|
1044
1146
|
throw new RequestError(-32603, err.message, {
|
|
@@ -1100,7 +1202,7 @@ function sliceLineRange(content, startLine, endLine) {
|
|
|
1100
1202
|
}
|
|
1101
1203
|
__name(sliceLineRange, "sliceLineRange");
|
|
1102
1204
|
var BridgeClient = class {
|
|
1103
|
-
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender) {
|
|
1205
|
+
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender, ownsSession = () => true) {
|
|
1104
1206
|
this.resolveEntry = resolveEntry;
|
|
1105
1207
|
this.resolvePendingRestoreEvents = resolvePendingRestoreEvents;
|
|
1106
1208
|
this.mediator = mediator;
|
|
@@ -1110,6 +1212,7 @@ var BridgeClient = class {
|
|
|
1110
1212
|
this.onModelPromoted = onModelPromoted;
|
|
1111
1213
|
this.onModePromoted = onModePromoted;
|
|
1112
1214
|
this.clientMcpSender = clientMcpSender;
|
|
1215
|
+
this.ownsSession = ownsSession;
|
|
1113
1216
|
}
|
|
1114
1217
|
static {
|
|
1115
1218
|
__name(this, "BridgeClient");
|
|
@@ -1163,14 +1266,32 @@ var BridgeClient = class {
|
|
|
1163
1266
|
}
|
|
1164
1267
|
}
|
|
1165
1268
|
async sessionUpdate(params) {
|
|
1269
|
+
if (!this.ownsSession(params.sessionId) && !this.inFlightRestoreIds.has(params.sessionId)) {
|
|
1270
|
+
writeStderrLine(
|
|
1271
|
+
`[demux] session=${params.sessionId} type=session_update action=dropped reason=session_not_owned`
|
|
1272
|
+
);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1166
1275
|
const entry = this.resolveEntry(params.sessionId);
|
|
1167
1276
|
const events = entry?.events ?? this.resolvePendingRestoreEvents(params.sessionId);
|
|
1168
1277
|
if (!events) return;
|
|
1278
|
+
const prepared = this.prepareSessionUpdateFrames(params, entry);
|
|
1279
|
+
for (const frame of prepared.frames) {
|
|
1280
|
+
events.publish(frame);
|
|
1281
|
+
}
|
|
1282
|
+
if (entry && prepared.artifacts.length > 0) {
|
|
1283
|
+
await this.upsertAndPublishArtifacts(entry, prepared.artifacts, {
|
|
1284
|
+
trustedPublisher: prepared.trustedPublisher
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
prepareSessionUpdateFrames(params, entry) {
|
|
1169
1289
|
const originator = entry?.activePromptOriginatorClientId ? { originatorClientId: entry.activePromptOriginatorClientId } : {};
|
|
1290
|
+
const frames = [];
|
|
1170
1291
|
const a2ui = extractA2uiToolUpdate(params);
|
|
1171
1292
|
if (a2ui) {
|
|
1172
1293
|
for (const surface of a2ui.surfaces) {
|
|
1173
|
-
|
|
1294
|
+
frames.push({
|
|
1174
1295
|
type: "session_update",
|
|
1175
1296
|
data: {
|
|
1176
1297
|
sessionId: params.sessionId,
|
|
@@ -1192,12 +1313,47 @@ var BridgeClient = class {
|
|
|
1192
1313
|
const updateMeta = params.update._meta;
|
|
1193
1314
|
const originalTs = updateMeta?.["serverTimestamp"] ?? updateMeta?.["timestamp"];
|
|
1194
1315
|
const serverTimestamp = typeof originalTs === "number" && Number.isFinite(originalTs) ? originalTs : void 0;
|
|
1195
|
-
|
|
1316
|
+
const artifacts = entry?.artifacts ? extractSessionUpdateArtifacts(
|
|
1317
|
+
params,
|
|
1318
|
+
updateMeta,
|
|
1319
|
+
entry.artifacts.inputBatchLimit(),
|
|
1320
|
+
entry.sessionId
|
|
1321
|
+
) : [];
|
|
1322
|
+
const publishParams = sanitizeSessionUpdateArtifacts(params, updateMeta);
|
|
1323
|
+
frames.push({
|
|
1196
1324
|
type: "session_update",
|
|
1197
|
-
data:
|
|
1325
|
+
data: publishParams,
|
|
1198
1326
|
...originator,
|
|
1199
1327
|
...serverTimestamp !== void 0 ? { _meta: { serverTimestamp } } : {}
|
|
1200
1328
|
});
|
|
1329
|
+
return {
|
|
1330
|
+
frames,
|
|
1331
|
+
artifacts,
|
|
1332
|
+
trustedPublisher: isTrustedArtifactToolUpdate(params, updateMeta)
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
async seedSessionUpdates(entry, updates) {
|
|
1336
|
+
const frames = [];
|
|
1337
|
+
const artifactBatches = [];
|
|
1338
|
+
for (const update of updates) {
|
|
1339
|
+
const prepared = this.prepareSessionUpdateFrames(
|
|
1340
|
+
{ sessionId: entry.sessionId, update },
|
|
1341
|
+
entry
|
|
1342
|
+
);
|
|
1343
|
+
frames.push(...prepared.frames);
|
|
1344
|
+
if (prepared.artifacts.length > 0) {
|
|
1345
|
+
artifactBatches.push({
|
|
1346
|
+
artifacts: prepared.artifacts,
|
|
1347
|
+
trustedPublisher: prepared.trustedPublisher
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
entry.events.seedReplayEvents(frames);
|
|
1352
|
+
for (const batch of artifactBatches) {
|
|
1353
|
+
await this.upsertAndPublishArtifacts(entry, batch.artifacts, {
|
|
1354
|
+
trustedPublisher: batch.trustedPublisher
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1201
1357
|
}
|
|
1202
1358
|
/**
|
|
1203
1359
|
* Bounded early-event buffer. Frames are keyed by sessionId; each
|
|
@@ -1335,11 +1491,12 @@ var BridgeClient = class {
|
|
|
1335
1491
|
return { payload: response };
|
|
1336
1492
|
}
|
|
1337
1493
|
/**
|
|
1338
|
-
* Handle child->bridge ACP `extNotification` calls.
|
|
1339
|
-
*
|
|
1494
|
+
* Handle child->bridge ACP `extNotification` calls. Recognized methods are
|
|
1495
|
+
* `qwen/notify/session/model-update`,
|
|
1340
1496
|
* `qwen/notify/session/mode-update`,
|
|
1341
1497
|
* `qwen/notify/session/title-update` (auto/in-process session titles),
|
|
1342
1498
|
* `qwen/notify/session/prompt-suggestion` (followup assist),
|
|
1499
|
+
* `qwen/notify/session/artifact-event` (hook artifacts),
|
|
1343
1500
|
* `qwen/notify/session/terminal-sequence`, and
|
|
1344
1501
|
* `qwen/notify/session/mcp-budget-event` — each translated into a
|
|
1345
1502
|
* session-scoped SSE frame. Unknown methods are dropped silently
|
|
@@ -1401,6 +1558,10 @@ var BridgeClient = class {
|
|
|
1401
1558
|
this.publishExtNotification(sessionId2, "terminal_sequence", rest2);
|
|
1402
1559
|
return;
|
|
1403
1560
|
}
|
|
1561
|
+
if (method === "qwen/notify/session/artifact-event") {
|
|
1562
|
+
await this.handleArtifactEvent(params);
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1404
1565
|
if (method !== "qwen/notify/session/mcp-budget-event") return;
|
|
1405
1566
|
const sessionId = params["sessionId"];
|
|
1406
1567
|
if (typeof sessionId !== "string") return;
|
|
@@ -1419,6 +1580,67 @@ var BridgeClient = class {
|
|
|
1419
1580
|
void _kind;
|
|
1420
1581
|
this.publishExtNotification(sessionId, type, rest);
|
|
1421
1582
|
}
|
|
1583
|
+
async handleArtifactEvent(params) {
|
|
1584
|
+
const sessionId = params["sessionId"];
|
|
1585
|
+
const rawArtifacts = params["artifacts"];
|
|
1586
|
+
if (typeof sessionId !== "string" || !Array.isArray(rawArtifacts)) {
|
|
1587
|
+
writeStderrLine(
|
|
1588
|
+
`[demux] session=${typeof sessionId === "string" ? sessionId : "<missing>"} type=artifact_event action=dropped reason=malformed`
|
|
1589
|
+
);
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
if (!this.ownsSession(sessionId) && !this.inFlightRestoreIds.has(sessionId)) {
|
|
1593
|
+
writeStderrLine(
|
|
1594
|
+
`[demux] session=${sessionId} type=artifact_event action=dropped reason=session_not_owned`
|
|
1595
|
+
);
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
const entry = this.resolveEntry(sessionId);
|
|
1599
|
+
if (!entry) {
|
|
1600
|
+
writeStderrLine(
|
|
1601
|
+
`[demux] session=${sessionId} type=artifact_event action=dropped reason=session_not_found`
|
|
1602
|
+
);
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
const hookEventName = typeof params["hookEventName"] === "string" ? params["hookEventName"] : void 0;
|
|
1606
|
+
const toolName = typeof params["toolName"] === "string" ? params["toolName"] : void 0;
|
|
1607
|
+
const toolCallId = typeof params["toolCallId"] === "string" ? params["toolCallId"] : void 0;
|
|
1608
|
+
const artifacts = extractCappedArtifactInputs(
|
|
1609
|
+
rawArtifacts,
|
|
1610
|
+
entry.artifacts.inputBatchLimit(),
|
|
1611
|
+
entry.sessionId,
|
|
1612
|
+
"hook",
|
|
1613
|
+
(artifact) => ({
|
|
1614
|
+
...artifactPayloadFields(artifact),
|
|
1615
|
+
source: "hook",
|
|
1616
|
+
hookEventName,
|
|
1617
|
+
toolName,
|
|
1618
|
+
toolCallId
|
|
1619
|
+
})
|
|
1620
|
+
);
|
|
1621
|
+
await this.upsertAndPublishArtifacts(entry, artifacts);
|
|
1622
|
+
}
|
|
1623
|
+
async upsertAndPublishArtifacts(entry, artifacts, options) {
|
|
1624
|
+
try {
|
|
1625
|
+
const result = await entry.artifacts.upsertMany(artifacts, options);
|
|
1626
|
+
this.publishArtifactChanges(entry, result.changes);
|
|
1627
|
+
} catch (error) {
|
|
1628
|
+
writeStderrLine(
|
|
1629
|
+
`[artifacts] session=${entry.sessionId} action=dropped reason=${JSON.stringify(
|
|
1630
|
+
artifactIngestionErrorReason(error)
|
|
1631
|
+
)}`
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
publishArtifactChanges(entry, changes) {
|
|
1636
|
+
for (const change of changes) {
|
|
1637
|
+
entry.events.publish({
|
|
1638
|
+
type: "artifact_changed",
|
|
1639
|
+
data: { sessionId: entry.sessionId, change },
|
|
1640
|
+
...entry.activePromptOriginatorClientId ? { originatorClientId: entry.activePromptOriginatorClientId } : {}
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1422
1644
|
publishExtNotification(sessionId, type, data) {
|
|
1423
1645
|
const entry = this.resolveEntry(sessionId);
|
|
1424
1646
|
const frame = {
|
|
@@ -1858,6 +2080,1005 @@ function extractA2uiToolUpdate(params) {
|
|
|
1858
2080
|
}
|
|
1859
2081
|
__name(extractA2uiToolUpdate, "extractA2uiToolUpdate");
|
|
1860
2082
|
|
|
2083
|
+
// packages/acp-bridge/src/sessionArtifacts.ts
|
|
2084
|
+
init_esbuild_shims();
|
|
2085
|
+
import { createHash } from "node:crypto";
|
|
2086
|
+
import { promises as fs2 } from "node:fs";
|
|
2087
|
+
import path2 from "node:path";
|
|
2088
|
+
var SOURCE_RESERVATIONS = {
|
|
2089
|
+
tool: 100,
|
|
2090
|
+
client: 50,
|
|
2091
|
+
hook: 50
|
|
2092
|
+
};
|
|
2093
|
+
var WORKSPACE_STATUS_REFRESH_TTL_MS = 5e3;
|
|
2094
|
+
var WORKSPACE_STATUS_REFRESH_BATCH_SIZE = 20;
|
|
2095
|
+
var SessionArtifactValidationError = class extends Error {
|
|
2096
|
+
constructor(message, field) {
|
|
2097
|
+
super(message);
|
|
2098
|
+
this.field = field;
|
|
2099
|
+
this.name = "SessionArtifactValidationError";
|
|
2100
|
+
}
|
|
2101
|
+
static {
|
|
2102
|
+
__name(this, "SessionArtifactValidationError");
|
|
2103
|
+
}
|
|
2104
|
+
code = "VALIDATION_FAILED";
|
|
2105
|
+
};
|
|
2106
|
+
var SessionArtifactStore = class {
|
|
2107
|
+
static {
|
|
2108
|
+
__name(this, "SessionArtifactStore");
|
|
2109
|
+
}
|
|
2110
|
+
sessionId;
|
|
2111
|
+
workspaceCwd;
|
|
2112
|
+
maxArtifacts;
|
|
2113
|
+
artifacts = /* @__PURE__ */ new Map();
|
|
2114
|
+
receivedSeq = 0;
|
|
2115
|
+
insertSeq = 0;
|
|
2116
|
+
realWorkspaceCwdPromise;
|
|
2117
|
+
operationQueue = Promise.resolve();
|
|
2118
|
+
constructor(options) {
|
|
2119
|
+
this.sessionId = options.sessionId;
|
|
2120
|
+
this.workspaceCwd = options.workspaceCwd;
|
|
2121
|
+
this.maxArtifacts = options.maxArtifacts ?? 200;
|
|
2122
|
+
}
|
|
2123
|
+
inputBatchLimit() {
|
|
2124
|
+
return this.maxArtifacts * 2;
|
|
2125
|
+
}
|
|
2126
|
+
async list() {
|
|
2127
|
+
return this.enqueue(async () => {
|
|
2128
|
+
await this.refreshWorkspaceStatuses();
|
|
2129
|
+
return {
|
|
2130
|
+
v: 1,
|
|
2131
|
+
sessionId: this.sessionId,
|
|
2132
|
+
artifacts: Array.from(this.artifacts.values()).sort((a, b) => a.insertSeq - b.insertSeq).map(toPublicArtifact),
|
|
2133
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2134
|
+
limits: { maxArtifacts: this.maxArtifacts }
|
|
2135
|
+
};
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
async upsertMany(inputs, options = {}) {
|
|
2139
|
+
return this.enqueue(async () => {
|
|
2140
|
+
const normalizedResults = [];
|
|
2141
|
+
for (const input of inputs) {
|
|
2142
|
+
try {
|
|
2143
|
+
normalizedResults.push(
|
|
2144
|
+
await this.normalizeInput(
|
|
2145
|
+
input,
|
|
2146
|
+
++this.receivedSeq,
|
|
2147
|
+
options.trustedPublisher === true
|
|
2148
|
+
)
|
|
2149
|
+
);
|
|
2150
|
+
} catch (error) {
|
|
2151
|
+
if (options.strict) {
|
|
2152
|
+
throw error;
|
|
2153
|
+
}
|
|
2154
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2155
|
+
writeStderrLine(
|
|
2156
|
+
`[artifacts] session=${this.sessionId} action=dropped reason=${JSON.stringify(
|
|
2157
|
+
message
|
|
2158
|
+
)}`
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
const changes = [];
|
|
2163
|
+
for (const artifact of coalesceByIdentity(normalizedResults)) {
|
|
2164
|
+
const existing = this.artifacts.get(artifact.id) ?? this.findPublishedUpgradeTarget(artifact) ?? this.findPublishedWorkspaceTarget(artifact);
|
|
2165
|
+
if (!existing) {
|
|
2166
|
+
const stored = {
|
|
2167
|
+
...artifact,
|
|
2168
|
+
insertSeq: ++this.insertSeq
|
|
2169
|
+
};
|
|
2170
|
+
this.artifacts.set(stored.id, stored);
|
|
2171
|
+
changes.push({
|
|
2172
|
+
action: "created",
|
|
2173
|
+
artifactId: stored.id,
|
|
2174
|
+
artifact: toPublicArtifact(stored)
|
|
2175
|
+
});
|
|
2176
|
+
continue;
|
|
2177
|
+
}
|
|
2178
|
+
const updated = mergeArtifact(existing, artifact);
|
|
2179
|
+
if (updated.changed) {
|
|
2180
|
+
if (updated.artifact.id !== existing.id) {
|
|
2181
|
+
this.artifacts.delete(existing.id);
|
|
2182
|
+
}
|
|
2183
|
+
this.artifacts.set(updated.artifact.id, updated.artifact);
|
|
2184
|
+
changes.push({
|
|
2185
|
+
action: "updated",
|
|
2186
|
+
artifactId: updated.artifact.id,
|
|
2187
|
+
artifact: toPublicArtifact(updated.artifact)
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
const createdIds = new Set(
|
|
2192
|
+
changes.filter((change) => change.action === "created").map((change) => change.artifactId)
|
|
2193
|
+
);
|
|
2194
|
+
changes.push(...await this.evictOverflow(createdIds, changes));
|
|
2195
|
+
return { v: 1, sessionId: this.sessionId, changes };
|
|
2196
|
+
});
|
|
2197
|
+
}
|
|
2198
|
+
findPublishedUpgradeTarget(artifact) {
|
|
2199
|
+
if (artifact.storage !== "published" || !artifact.trustedPublisher || !artifact.managedId || !artifact.url) {
|
|
2200
|
+
return void 0;
|
|
2201
|
+
}
|
|
2202
|
+
const byUrl = this.artifacts.get(
|
|
2203
|
+
stableArtifactId(this.sessionId, `url:${artifact.url}`)
|
|
2204
|
+
);
|
|
2205
|
+
if (byUrl && (byUrl.storage !== "published" || byUrl.managedId === artifact.managedId)) {
|
|
2206
|
+
return byUrl;
|
|
2207
|
+
}
|
|
2208
|
+
for (const existing of this.artifacts.values()) {
|
|
2209
|
+
if (existing.storage === "workspace" && existing.workspacePath && artifact.managedId === managedIdForWorkspacePath(
|
|
2210
|
+
this.workspaceCwd,
|
|
2211
|
+
existing.workspacePath
|
|
2212
|
+
) || existing.storage === "published" && existing.managedId === artifact.managedId) {
|
|
2213
|
+
return existing;
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
return void 0;
|
|
2217
|
+
}
|
|
2218
|
+
findPublishedWorkspaceTarget(artifact) {
|
|
2219
|
+
if (artifact.storage !== "workspace" || !artifact.workspacePath) {
|
|
2220
|
+
return void 0;
|
|
2221
|
+
}
|
|
2222
|
+
const managedId = managedIdForWorkspacePath(
|
|
2223
|
+
this.workspaceCwd,
|
|
2224
|
+
artifact.workspacePath
|
|
2225
|
+
);
|
|
2226
|
+
for (const existing of this.artifacts.values()) {
|
|
2227
|
+
if (existing.storage === "published" && existing.managedId === managedId) {
|
|
2228
|
+
return existing;
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
return void 0;
|
|
2232
|
+
}
|
|
2233
|
+
async remove(artifactId, options) {
|
|
2234
|
+
return this.enqueue(async () => {
|
|
2235
|
+
const existing = this.artifacts.get(artifactId);
|
|
2236
|
+
if (!existing) {
|
|
2237
|
+
return { v: 1, sessionId: this.sessionId, changes: [] };
|
|
2238
|
+
}
|
|
2239
|
+
if (existing.source === "client" && existing.clientId !== void 0 && existing.clientId !== options?.clientId) {
|
|
2240
|
+
writeStderrLine(
|
|
2241
|
+
`[artifacts] session=${this.sessionId} action=remove_denied artifactId=${artifactId} owner=${existing.clientId} requester=${options?.clientId ?? "<anonymous>"}`
|
|
2242
|
+
);
|
|
2243
|
+
return { v: 1, sessionId: this.sessionId, changes: [] };
|
|
2244
|
+
}
|
|
2245
|
+
this.artifacts.delete(artifactId);
|
|
2246
|
+
return {
|
|
2247
|
+
v: 1,
|
|
2248
|
+
sessionId: this.sessionId,
|
|
2249
|
+
changes: [
|
|
2250
|
+
{
|
|
2251
|
+
action: "removed",
|
|
2252
|
+
artifactId,
|
|
2253
|
+
artifact: toPublicArtifact(existing),
|
|
2254
|
+
reason: "explicit"
|
|
2255
|
+
}
|
|
2256
|
+
]
|
|
2257
|
+
};
|
|
2258
|
+
});
|
|
2259
|
+
}
|
|
2260
|
+
enqueue(operation) {
|
|
2261
|
+
const result = this.operationQueue.then(operation, operation);
|
|
2262
|
+
this.operationQueue = result.then(
|
|
2263
|
+
() => void 0,
|
|
2264
|
+
() => void 0
|
|
2265
|
+
);
|
|
2266
|
+
return result;
|
|
2267
|
+
}
|
|
2268
|
+
async normalizeInput(input, receivedSeq, trustedPublisherFromCaller) {
|
|
2269
|
+
if (!input || typeof input !== "object") {
|
|
2270
|
+
throw new SessionArtifactValidationError("Artifact must be an object");
|
|
2271
|
+
}
|
|
2272
|
+
const title = normalizeString(input.title, "title", 200, true);
|
|
2273
|
+
const description = normalizeString(
|
|
2274
|
+
input.description,
|
|
2275
|
+
"description",
|
|
2276
|
+
1e3,
|
|
2277
|
+
false
|
|
2278
|
+
);
|
|
2279
|
+
const source = input.source ?? "tool";
|
|
2280
|
+
if (source !== "tool" && source !== "hook" && source !== "client") {
|
|
2281
|
+
throw new SessionArtifactValidationError(
|
|
2282
|
+
"source must be tool, hook, or client",
|
|
2283
|
+
"source"
|
|
2284
|
+
);
|
|
2285
|
+
}
|
|
2286
|
+
const trustedPublisher = trustedPublisherFromCaller;
|
|
2287
|
+
const workspacePath = input.workspacePath ? normalizeWorkspacePath(input.workspacePath, this.workspaceCwd) : void 0;
|
|
2288
|
+
const managedId = normalizeManagedId(input.managedId);
|
|
2289
|
+
const rawStorage = input.storage;
|
|
2290
|
+
const storage = inferStorage(rawStorage, {
|
|
2291
|
+
workspacePath,
|
|
2292
|
+
managedId,
|
|
2293
|
+
url: input.url,
|
|
2294
|
+
trustedPublisher
|
|
2295
|
+
});
|
|
2296
|
+
const url = input.url ? normalizeArtifactUrl(input.url, trustedPublisher) : void 0;
|
|
2297
|
+
validateLocator(storage, {
|
|
2298
|
+
workspacePath,
|
|
2299
|
+
managedId,
|
|
2300
|
+
url,
|
|
2301
|
+
trustedPublisher
|
|
2302
|
+
});
|
|
2303
|
+
const metadata = normalizeMetadata(input.metadata);
|
|
2304
|
+
const workspaceStatus = workspacePath ? await this.getInitialWorkspaceStatus(workspacePath) : void 0;
|
|
2305
|
+
if (workspaceStatus?.escaped) {
|
|
2306
|
+
throw new SessionArtifactValidationError(
|
|
2307
|
+
"workspacePath must stay inside the workspace",
|
|
2308
|
+
"workspacePath"
|
|
2309
|
+
);
|
|
2310
|
+
}
|
|
2311
|
+
const kind = normalizeKind(
|
|
2312
|
+
input.kind ?? inferKind({ storage, workspacePath, url })
|
|
2313
|
+
);
|
|
2314
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2315
|
+
const identityKey = buildIdentityKey({
|
|
2316
|
+
storage,
|
|
2317
|
+
workspacePath,
|
|
2318
|
+
managedId,
|
|
2319
|
+
url
|
|
2320
|
+
});
|
|
2321
|
+
const id = stableArtifactId(this.sessionId, identityKey);
|
|
2322
|
+
return {
|
|
2323
|
+
id,
|
|
2324
|
+
identityKey,
|
|
2325
|
+
receivedSeq,
|
|
2326
|
+
retentionSource: source,
|
|
2327
|
+
trustedPublisher,
|
|
2328
|
+
kind,
|
|
2329
|
+
storage,
|
|
2330
|
+
source,
|
|
2331
|
+
status: workspaceStatus?.status ?? "available",
|
|
2332
|
+
...workspacePath ? { lastStatAt: Date.now() } : {},
|
|
2333
|
+
title,
|
|
2334
|
+
description,
|
|
2335
|
+
workspacePath,
|
|
2336
|
+
managedId,
|
|
2337
|
+
url,
|
|
2338
|
+
mimeType: normalizeString(input.mimeType, "mimeType", 120, false),
|
|
2339
|
+
sizeBytes: input.sizeBytes !== void 0 ? normalizeSizeBytes(input.sizeBytes) : workspaceStatus?.sizeBytes,
|
|
2340
|
+
metadata,
|
|
2341
|
+
clientRetained: source === "client",
|
|
2342
|
+
createdAt: now,
|
|
2343
|
+
updatedAt: now,
|
|
2344
|
+
toolCallId: normalizeString(input.toolCallId, "toolCallId", 200, false),
|
|
2345
|
+
toolName: normalizeString(input.toolName, "toolName", 200, false),
|
|
2346
|
+
hookEventName: normalizeString(
|
|
2347
|
+
input.hookEventName,
|
|
2348
|
+
"hookEventName",
|
|
2349
|
+
200,
|
|
2350
|
+
false
|
|
2351
|
+
),
|
|
2352
|
+
clientId: normalizeString(input.clientId, "clientId", 200, false)
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
async refreshWorkspaceStatuses() {
|
|
2356
|
+
const now = Date.now();
|
|
2357
|
+
const staleWorkspaceArtifacts = Array.from(this.artifacts.values()).filter((artifact) => artifact.workspacePath).filter((artifact) => shouldRefreshWorkspaceStatus(artifact, now));
|
|
2358
|
+
await runInBatches(
|
|
2359
|
+
staleWorkspaceArtifacts,
|
|
2360
|
+
WORKSPACE_STATUS_REFRESH_BATCH_SIZE,
|
|
2361
|
+
(artifact) => this.refreshWorkspaceStatus(artifact, {
|
|
2362
|
+
onError: "missing",
|
|
2363
|
+
now
|
|
2364
|
+
})
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
async getInitialWorkspaceStatus(workspacePath) {
|
|
2368
|
+
try {
|
|
2369
|
+
return await getWorkspaceStatus(
|
|
2370
|
+
this.workspaceCwd,
|
|
2371
|
+
workspacePath,
|
|
2372
|
+
this.getRealWorkspaceCwd()
|
|
2373
|
+
);
|
|
2374
|
+
} catch (error) {
|
|
2375
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
2376
|
+
throw new SessionArtifactValidationError(
|
|
2377
|
+
`workspacePath could not be inspected: ${reason}`,
|
|
2378
|
+
"workspacePath"
|
|
2379
|
+
);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
async refreshWorkspaceStatus(artifact, options) {
|
|
2383
|
+
if (!artifact.workspacePath) {
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
try {
|
|
2387
|
+
const status = await getWorkspaceStatus(
|
|
2388
|
+
this.workspaceCwd,
|
|
2389
|
+
artifact.workspacePath,
|
|
2390
|
+
this.getRealWorkspaceCwd()
|
|
2391
|
+
);
|
|
2392
|
+
artifact.status = status.status;
|
|
2393
|
+
artifact.sizeBytes = status.sizeBytes;
|
|
2394
|
+
if (status.escaped) {
|
|
2395
|
+
artifact.status = "missing";
|
|
2396
|
+
artifact.sizeBytes = void 0;
|
|
2397
|
+
delete artifact.workspacePath;
|
|
2398
|
+
}
|
|
2399
|
+
artifact.lastStatAt = options.now ?? Date.now();
|
|
2400
|
+
} catch (error) {
|
|
2401
|
+
writeStderrLine(
|
|
2402
|
+
`[artifacts] session=${this.sessionId} action=status_refresh_failed artifactId=${artifact.id} reason=${JSON.stringify(
|
|
2403
|
+
error instanceof Error ? error.message : String(error)
|
|
2404
|
+
)}`
|
|
2405
|
+
);
|
|
2406
|
+
if (options.onError === "missing") {
|
|
2407
|
+
artifact.status = "missing";
|
|
2408
|
+
artifact.sizeBytes = void 0;
|
|
2409
|
+
artifact.lastStatAt = options.now ?? Date.now();
|
|
2410
|
+
}
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
getRealWorkspaceCwd() {
|
|
2415
|
+
if (!this.realWorkspaceCwdPromise) {
|
|
2416
|
+
const promise = fs2.realpath(this.workspaceCwd).catch((error) => {
|
|
2417
|
+
if (this.realWorkspaceCwdPromise === promise) {
|
|
2418
|
+
this.realWorkspaceCwdPromise = void 0;
|
|
2419
|
+
}
|
|
2420
|
+
throw error;
|
|
2421
|
+
});
|
|
2422
|
+
this.realWorkspaceCwdPromise = promise;
|
|
2423
|
+
}
|
|
2424
|
+
return this.realWorkspaceCwdPromise;
|
|
2425
|
+
}
|
|
2426
|
+
async evictOverflow(createdIds, changes) {
|
|
2427
|
+
const removed = [];
|
|
2428
|
+
if (this.artifacts.size <= this.maxArtifacts) {
|
|
2429
|
+
return removed;
|
|
2430
|
+
}
|
|
2431
|
+
const createdInThisBatch = new Set(createdIds);
|
|
2432
|
+
const candidates = Array.from(this.artifacts.values()).filter(
|
|
2433
|
+
(artifact) => !createdInThisBatch.has(artifact.id)
|
|
2434
|
+
);
|
|
2435
|
+
const now = Date.now();
|
|
2436
|
+
const staleWorkspaceCandidates = candidates.filter((artifact) => artifact.workspacePath).filter((artifact) => shouldRefreshWorkspaceStatus(artifact, now));
|
|
2437
|
+
await runInBatches(
|
|
2438
|
+
staleWorkspaceCandidates,
|
|
2439
|
+
WORKSPACE_STATUS_REFRESH_BATCH_SIZE,
|
|
2440
|
+
(artifact) => this.refreshWorkspaceStatus(artifact, { onError: "preserve", now })
|
|
2441
|
+
);
|
|
2442
|
+
const sourceCounts = countByRetentionSource(this.artifacts.values());
|
|
2443
|
+
while (this.artifacts.size > this.maxArtifacts) {
|
|
2444
|
+
const artifact = selectEvictionCandidate(candidates, sourceCounts);
|
|
2445
|
+
if (!artifact) break;
|
|
2446
|
+
this.artifacts.delete(artifact.id);
|
|
2447
|
+
candidates.splice(candidates.indexOf(artifact), 1);
|
|
2448
|
+
sourceCounts[artifact.retentionSource]--;
|
|
2449
|
+
removePriorChange(changes, artifact.id);
|
|
2450
|
+
removed.push({
|
|
2451
|
+
action: "removed",
|
|
2452
|
+
artifactId: artifact.id,
|
|
2453
|
+
artifact: toPublicArtifact(artifact),
|
|
2454
|
+
reason: "eviction"
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2457
|
+
const overflowCreated = Array.from(this.artifacts.values()).filter((artifact) => createdInThisBatch.has(artifact.id)).sort((a, b) => b.receivedSeq - a.receivedSeq);
|
|
2458
|
+
for (const artifact of overflowCreated) {
|
|
2459
|
+
if (this.artifacts.size <= this.maxArtifacts) {
|
|
2460
|
+
break;
|
|
2461
|
+
}
|
|
2462
|
+
this.artifacts.delete(artifact.id);
|
|
2463
|
+
writeStderrLine(
|
|
2464
|
+
`[artifacts] session=${this.sessionId} action=dropped reason="max artifacts exceeded" artifactId=${artifact.id}`
|
|
2465
|
+
);
|
|
2466
|
+
removePriorChange(changes, artifact.id);
|
|
2467
|
+
}
|
|
2468
|
+
return removed;
|
|
2469
|
+
}
|
|
2470
|
+
};
|
|
2471
|
+
function coalesceByIdentity(artifacts) {
|
|
2472
|
+
const byId = /* @__PURE__ */ new Map();
|
|
2473
|
+
for (const artifact of artifacts) {
|
|
2474
|
+
const existing = byId.get(artifact.id);
|
|
2475
|
+
if (!existing) {
|
|
2476
|
+
byId.set(artifact.id, artifact);
|
|
2477
|
+
continue;
|
|
2478
|
+
}
|
|
2479
|
+
byId.set(artifact.id, mergeBatchArtifact(existing, artifact));
|
|
2480
|
+
}
|
|
2481
|
+
return Array.from(byId.values()).sort(
|
|
2482
|
+
(a, b) => a.receivedSeq - b.receivedSeq
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
__name(coalesceByIdentity, "coalesceByIdentity");
|
|
2486
|
+
function mergeBatchArtifact(existing, next) {
|
|
2487
|
+
const publishedUpgrade = existing.storage !== "published" && next.storage === "published" && next.trustedPublisher;
|
|
2488
|
+
if (publishedUpgrade) {
|
|
2489
|
+
const merged = {
|
|
2490
|
+
...existing,
|
|
2491
|
+
id: next.id,
|
|
2492
|
+
identityKey: next.identityKey,
|
|
2493
|
+
kind: next.kind,
|
|
2494
|
+
storage: "published",
|
|
2495
|
+
status: next.status,
|
|
2496
|
+
title: next.title,
|
|
2497
|
+
description: next.description,
|
|
2498
|
+
managedId: next.managedId ?? existing.managedId,
|
|
2499
|
+
url: next.url ?? existing.url,
|
|
2500
|
+
mimeType: next.mimeType ?? existing.mimeType,
|
|
2501
|
+
sizeBytes: next.sizeBytes ?? existing.sizeBytes,
|
|
2502
|
+
metadata: mergeMetadata(existing, next),
|
|
2503
|
+
trustedPublisher: true,
|
|
2504
|
+
createdAt: existing.createdAt,
|
|
2505
|
+
receivedSeq: existing.receivedSeq,
|
|
2506
|
+
retentionSource: existing.retentionSource,
|
|
2507
|
+
clientRetained: existing.clientRetained || next.clientRetained,
|
|
2508
|
+
lastStatAt: void 0
|
|
2509
|
+
};
|
|
2510
|
+
delete merged.workspacePath;
|
|
2511
|
+
return merged;
|
|
2512
|
+
}
|
|
2513
|
+
return {
|
|
2514
|
+
...existing,
|
|
2515
|
+
status: next.status,
|
|
2516
|
+
sizeBytes: mergeSizeBytes(existing, next),
|
|
2517
|
+
metadata: mergeMetadata(existing, next),
|
|
2518
|
+
clientRetained: existing.clientRetained || next.clientRetained,
|
|
2519
|
+
trustedPublisher: existing.trustedPublisher || next.trustedPublisher,
|
|
2520
|
+
lastStatAt: next.lastStatAt ?? existing.lastStatAt
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
__name(mergeBatchArtifact, "mergeBatchArtifact");
|
|
2524
|
+
function mergeArtifact(existing, incoming) {
|
|
2525
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2526
|
+
const publishedUpgrade = existing.storage !== "published" && incoming.storage === "published" && incoming.trustedPublisher;
|
|
2527
|
+
const publishedRefresh = existing.storage === "published" && incoming.storage === "published" && incoming.trustedPublisher && incoming.managedId !== void 0 && incoming.managedId === existing.managedId;
|
|
2528
|
+
const publishedUpdate = publishedUpgrade || publishedRefresh;
|
|
2529
|
+
const next = {
|
|
2530
|
+
...existing,
|
|
2531
|
+
id: publishedUpdate ? incoming.id : existing.id,
|
|
2532
|
+
identityKey: publishedUpdate ? incoming.identityKey : existing.identityKey,
|
|
2533
|
+
kind: publishedUpdate ? incoming.kind : existing.kind,
|
|
2534
|
+
storage: publishedUpgrade ? "published" : existing.storage,
|
|
2535
|
+
status: existing.storage === "published" && !publishedUpdate ? existing.status : incoming.status,
|
|
2536
|
+
managedId: publishedUpdate ? incoming.managedId ?? existing.managedId : existing.managedId,
|
|
2537
|
+
url: publishedUpdate ? incoming.url ?? existing.url : existing.url,
|
|
2538
|
+
workspacePath: publishedUpdate || existing.storage === "published" ? void 0 : existing.workspacePath ?? incoming.workspacePath,
|
|
2539
|
+
mimeType: publishedUpdate ? incoming.mimeType ?? existing.mimeType : existing.mimeType,
|
|
2540
|
+
sizeBytes: existing.storage === "published" && !publishedUpdate ? existing.sizeBytes : mergeSizeBytes(existing, incoming),
|
|
2541
|
+
metadata: existing.storage === "published" && !publishedUpdate ? existing.metadata : mergeMetadata(existing, incoming),
|
|
2542
|
+
source: existing.source,
|
|
2543
|
+
retentionSource: existing.retentionSource,
|
|
2544
|
+
trustedPublisher: existing.trustedPublisher || incoming.trustedPublisher,
|
|
2545
|
+
clientRetained: existing.clientRetained || incoming.clientRetained,
|
|
2546
|
+
lastStatAt: publishedUpdate || existing.storage === "published" ? void 0 : incoming.lastStatAt ?? existing.lastStatAt,
|
|
2547
|
+
updatedAt: existing.updatedAt
|
|
2548
|
+
};
|
|
2549
|
+
if (publishedUpdate) {
|
|
2550
|
+
next.title = incoming.title;
|
|
2551
|
+
next.description = incoming.description;
|
|
2552
|
+
delete next.workspacePath;
|
|
2553
|
+
}
|
|
2554
|
+
const changed = !publicArtifactsEqual(
|
|
2555
|
+
toPublicArtifact(existing),
|
|
2556
|
+
toPublicArtifact(next)
|
|
2557
|
+
);
|
|
2558
|
+
if (changed) {
|
|
2559
|
+
next.updatedAt = now;
|
|
2560
|
+
}
|
|
2561
|
+
return { artifact: changed ? next : existing, changed };
|
|
2562
|
+
}
|
|
2563
|
+
__name(mergeArtifact, "mergeArtifact");
|
|
2564
|
+
function publicArtifactsEqual(a, b) {
|
|
2565
|
+
return a.id === b.id && a.kind === b.kind && a.storage === b.storage && a.source === b.source && a.status === b.status && a.title === b.title && a.description === b.description && a.workspacePath === b.workspacePath && a.managedId === b.managedId && a.url === b.url && a.mimeType === b.mimeType && a.sizeBytes === b.sizeBytes && metadataEqual(a.metadata, b.metadata) && a.clientRetained === b.clientRetained && a.createdAt === b.createdAt && a.toolCallId === b.toolCallId && a.toolName === b.toolName && a.hookEventName === b.hookEventName && a.clientId === b.clientId;
|
|
2566
|
+
}
|
|
2567
|
+
__name(publicArtifactsEqual, "publicArtifactsEqual");
|
|
2568
|
+
function metadataEqual(a, b) {
|
|
2569
|
+
if (a === b) return true;
|
|
2570
|
+
if (!a || !b) return false;
|
|
2571
|
+
const aKeys = Object.keys(a);
|
|
2572
|
+
const bKeys = Object.keys(b);
|
|
2573
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
2574
|
+
return aKeys.every((key) => Object.hasOwn(b, key) && a[key] === b[key]);
|
|
2575
|
+
}
|
|
2576
|
+
__name(metadataEqual, "metadataEqual");
|
|
2577
|
+
function mergeSizeBytes(existing, incoming) {
|
|
2578
|
+
if (incoming.sizeBytes !== void 0) {
|
|
2579
|
+
return incoming.sizeBytes;
|
|
2580
|
+
}
|
|
2581
|
+
if (incoming.workspacePath && incoming.status === "missing") {
|
|
2582
|
+
return void 0;
|
|
2583
|
+
}
|
|
2584
|
+
return existing.sizeBytes;
|
|
2585
|
+
}
|
|
2586
|
+
__name(mergeSizeBytes, "mergeSizeBytes");
|
|
2587
|
+
function mergeMetadata(existing, incoming) {
|
|
2588
|
+
if (!incoming.metadata || incoming.source === "hook" || incoming.source !== existing.source) {
|
|
2589
|
+
return existing.metadata;
|
|
2590
|
+
}
|
|
2591
|
+
const merged = { ...existing.metadata ?? {} };
|
|
2592
|
+
let changed = false;
|
|
2593
|
+
for (const [key, value] of Object.entries(incoming.metadata)) {
|
|
2594
|
+
if (!Object.hasOwn(merged, key)) {
|
|
2595
|
+
merged[key] = value;
|
|
2596
|
+
changed = true;
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
if (!changed) {
|
|
2600
|
+
return existing.metadata;
|
|
2601
|
+
}
|
|
2602
|
+
if (!isMetadataWithinLimit(merged)) {
|
|
2603
|
+
writeStderrLine(
|
|
2604
|
+
`[artifacts] action=metadata_merge_dropped artifactId=${incoming.id} reason="metadata limit exceeded"`
|
|
2605
|
+
);
|
|
2606
|
+
return existing.metadata;
|
|
2607
|
+
}
|
|
2608
|
+
return merged;
|
|
2609
|
+
}
|
|
2610
|
+
__name(mergeMetadata, "mergeMetadata");
|
|
2611
|
+
function isMetadataWithinLimit(metadata) {
|
|
2612
|
+
return Buffer.byteLength(JSON.stringify(metadata), "utf8") <= 4096;
|
|
2613
|
+
}
|
|
2614
|
+
__name(isMetadataWithinLimit, "isMetadataWithinLimit");
|
|
2615
|
+
function countByRetentionSource(artifacts) {
|
|
2616
|
+
const counts = {
|
|
2617
|
+
tool: 0,
|
|
2618
|
+
client: 0,
|
|
2619
|
+
hook: 0
|
|
2620
|
+
};
|
|
2621
|
+
for (const artifact of artifacts) {
|
|
2622
|
+
counts[artifact.retentionSource]++;
|
|
2623
|
+
}
|
|
2624
|
+
return counts;
|
|
2625
|
+
}
|
|
2626
|
+
__name(countByRetentionSource, "countByRetentionSource");
|
|
2627
|
+
function shouldRefreshWorkspaceStatus(artifact, now) {
|
|
2628
|
+
return artifact.lastStatAt === void 0 || now - artifact.lastStatAt >= WORKSPACE_STATUS_REFRESH_TTL_MS;
|
|
2629
|
+
}
|
|
2630
|
+
__name(shouldRefreshWorkspaceStatus, "shouldRefreshWorkspaceStatus");
|
|
2631
|
+
function selectEvictionCandidate(candidates, sourceCounts) {
|
|
2632
|
+
return oldest(
|
|
2633
|
+
candidates,
|
|
2634
|
+
(artifact) => artifact.status === "missing" && !artifact.clientRetained
|
|
2635
|
+
) ?? oldest(
|
|
2636
|
+
candidates,
|
|
2637
|
+
(artifact) => !artifact.clientRetained && sourceCounts[artifact.retentionSource] > SOURCE_RESERVATIONS[artifact.retentionSource]
|
|
2638
|
+
) ?? oldest(candidates, (artifact) => !artifact.clientRetained) ?? oldest(candidates);
|
|
2639
|
+
}
|
|
2640
|
+
__name(selectEvictionCandidate, "selectEvictionCandidate");
|
|
2641
|
+
function oldest(artifacts, predicate = () => true) {
|
|
2642
|
+
let selected;
|
|
2643
|
+
for (const artifact of artifacts) {
|
|
2644
|
+
if (!predicate(artifact)) {
|
|
2645
|
+
continue;
|
|
2646
|
+
}
|
|
2647
|
+
if (!selected || compareOldest(artifact, selected) < 0) {
|
|
2648
|
+
selected = artifact;
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
return selected;
|
|
2652
|
+
}
|
|
2653
|
+
__name(oldest, "oldest");
|
|
2654
|
+
function compareOldest(a, b) {
|
|
2655
|
+
const created = a.createdAt.localeCompare(b.createdAt);
|
|
2656
|
+
if (created !== 0) return created;
|
|
2657
|
+
return a.insertSeq - b.insertSeq;
|
|
2658
|
+
}
|
|
2659
|
+
__name(compareOldest, "compareOldest");
|
|
2660
|
+
function removePriorChange(changes, artifactId) {
|
|
2661
|
+
const index = changes.findIndex((change) => change.artifactId === artifactId);
|
|
2662
|
+
if (index >= 0) {
|
|
2663
|
+
changes.splice(index, 1);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
__name(removePriorChange, "removePriorChange");
|
|
2667
|
+
function toPublicArtifact(artifact) {
|
|
2668
|
+
const {
|
|
2669
|
+
id,
|
|
2670
|
+
kind,
|
|
2671
|
+
storage,
|
|
2672
|
+
source,
|
|
2673
|
+
status,
|
|
2674
|
+
title,
|
|
2675
|
+
description,
|
|
2676
|
+
workspacePath,
|
|
2677
|
+
managedId,
|
|
2678
|
+
url,
|
|
2679
|
+
mimeType,
|
|
2680
|
+
sizeBytes,
|
|
2681
|
+
metadata,
|
|
2682
|
+
clientRetained,
|
|
2683
|
+
createdAt,
|
|
2684
|
+
updatedAt,
|
|
2685
|
+
toolCallId,
|
|
2686
|
+
toolName,
|
|
2687
|
+
hookEventName,
|
|
2688
|
+
clientId
|
|
2689
|
+
} = artifact;
|
|
2690
|
+
return {
|
|
2691
|
+
id,
|
|
2692
|
+
kind,
|
|
2693
|
+
storage,
|
|
2694
|
+
source,
|
|
2695
|
+
status,
|
|
2696
|
+
title,
|
|
2697
|
+
...description ? { description } : {},
|
|
2698
|
+
...workspacePath ? { workspacePath } : {},
|
|
2699
|
+
...managedId ? { managedId } : {},
|
|
2700
|
+
...url ? { url } : {},
|
|
2701
|
+
...mimeType ? { mimeType } : {},
|
|
2702
|
+
...sizeBytes !== void 0 ? { sizeBytes } : {},
|
|
2703
|
+
...metadata ? { metadata } : {},
|
|
2704
|
+
clientRetained,
|
|
2705
|
+
createdAt,
|
|
2706
|
+
updatedAt,
|
|
2707
|
+
...toolCallId ? { toolCallId } : {},
|
|
2708
|
+
...toolName ? { toolName } : {},
|
|
2709
|
+
...hookEventName ? { hookEventName } : {},
|
|
2710
|
+
...clientId ? { clientId } : {}
|
|
2711
|
+
};
|
|
2712
|
+
}
|
|
2713
|
+
__name(toPublicArtifact, "toPublicArtifact");
|
|
2714
|
+
function inferStorage(requested, locators) {
|
|
2715
|
+
if (requested !== void 0 && typeof requested !== "string") {
|
|
2716
|
+
throw new SessionArtifactValidationError(
|
|
2717
|
+
"storage must be a string",
|
|
2718
|
+
"storage"
|
|
2719
|
+
);
|
|
2720
|
+
}
|
|
2721
|
+
if (requested) {
|
|
2722
|
+
if (requested !== "workspace" && requested !== "external_url" && requested !== "managed" && requested !== "published") {
|
|
2723
|
+
throw new SessionArtifactValidationError(
|
|
2724
|
+
"storage must be workspace, external_url, managed, or published",
|
|
2725
|
+
"storage"
|
|
2726
|
+
);
|
|
2727
|
+
}
|
|
2728
|
+
return requested;
|
|
2729
|
+
}
|
|
2730
|
+
if (locators.workspacePath) return "workspace";
|
|
2731
|
+
if (locators.managedId) return "managed";
|
|
2732
|
+
if (locators.url && locators.trustedPublisher) return "published";
|
|
2733
|
+
return "external_url";
|
|
2734
|
+
}
|
|
2735
|
+
__name(inferStorage, "inferStorage");
|
|
2736
|
+
function normalizeKind(kind) {
|
|
2737
|
+
if (kind === "file" || kind === "link" || kind === "html" || kind === "image" || kind === "video" || kind === "audio" || kind === "pdf" || kind === "notebook" || kind === "other") {
|
|
2738
|
+
return kind;
|
|
2739
|
+
}
|
|
2740
|
+
throw new SessionArtifactValidationError(
|
|
2741
|
+
"kind must be a supported artifact kind",
|
|
2742
|
+
"kind"
|
|
2743
|
+
);
|
|
2744
|
+
}
|
|
2745
|
+
__name(normalizeKind, "normalizeKind");
|
|
2746
|
+
function validateLocator(storage, locators) {
|
|
2747
|
+
if (storage === "published") {
|
|
2748
|
+
if (!locators.trustedPublisher) {
|
|
2749
|
+
throw new SessionArtifactValidationError(
|
|
2750
|
+
"published artifacts are reserved for trusted publishers",
|
|
2751
|
+
"storage"
|
|
2752
|
+
);
|
|
2753
|
+
}
|
|
2754
|
+
if (!locators.url) {
|
|
2755
|
+
throw new SessionArtifactValidationError(
|
|
2756
|
+
"published artifacts require url",
|
|
2757
|
+
"url"
|
|
2758
|
+
);
|
|
2759
|
+
}
|
|
2760
|
+
if (locators.workspacePath) {
|
|
2761
|
+
throw new SessionArtifactValidationError(
|
|
2762
|
+
"published artifacts cannot include workspacePath",
|
|
2763
|
+
"workspacePath"
|
|
2764
|
+
);
|
|
2765
|
+
}
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
const locatorCount = [
|
|
2769
|
+
locators.workspacePath,
|
|
2770
|
+
locators.managedId,
|
|
2771
|
+
locators.url
|
|
2772
|
+
].filter(Boolean).length;
|
|
2773
|
+
if (locatorCount !== 1) {
|
|
2774
|
+
throw new SessionArtifactValidationError(
|
|
2775
|
+
"provide exactly one of workspacePath, managedId, or url"
|
|
2776
|
+
);
|
|
2777
|
+
}
|
|
2778
|
+
if (storage === "workspace" && !locators.workspacePath) {
|
|
2779
|
+
throw new SessionArtifactValidationError(
|
|
2780
|
+
"workspace storage requires workspacePath",
|
|
2781
|
+
"workspacePath"
|
|
2782
|
+
);
|
|
2783
|
+
}
|
|
2784
|
+
if (storage === "managed" && !locators.managedId) {
|
|
2785
|
+
throw new SessionArtifactValidationError(
|
|
2786
|
+
"managed storage requires managedId",
|
|
2787
|
+
"managedId"
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
if (storage === "external_url" && !locators.url) {
|
|
2791
|
+
throw new SessionArtifactValidationError(
|
|
2792
|
+
"external_url storage requires url",
|
|
2793
|
+
"url"
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
__name(validateLocator, "validateLocator");
|
|
2798
|
+
function buildIdentityKey(input) {
|
|
2799
|
+
if (input.workspacePath) return `workspace:${input.workspacePath}`;
|
|
2800
|
+
if (input.managedId) return `managed:${input.managedId}`;
|
|
2801
|
+
if (input.url) return `url:${input.url}`;
|
|
2802
|
+
throw new SessionArtifactValidationError(
|
|
2803
|
+
"artifact identity requires workspacePath, managedId, or url"
|
|
2804
|
+
);
|
|
2805
|
+
}
|
|
2806
|
+
__name(buildIdentityKey, "buildIdentityKey");
|
|
2807
|
+
function stableArtifactId(sessionId, identityKey) {
|
|
2808
|
+
return createHash("sha256").update(`${sessionId}:${identityKey}`).digest("hex").slice(0, 16);
|
|
2809
|
+
}
|
|
2810
|
+
__name(stableArtifactId, "stableArtifactId");
|
|
2811
|
+
function managedIdForWorkspacePath(workspaceCwd, workspacePath) {
|
|
2812
|
+
return createHash("sha1").update(path2.resolve(workspaceCwd, workspacePath)).digest("hex").slice(0, 16);
|
|
2813
|
+
}
|
|
2814
|
+
__name(managedIdForWorkspacePath, "managedIdForWorkspacePath");
|
|
2815
|
+
function normalizeString(value, field, maxLength, required) {
|
|
2816
|
+
if (value === void 0 || value === null) {
|
|
2817
|
+
if (required) {
|
|
2818
|
+
throw new SessionArtifactValidationError(`${field} is required`, field);
|
|
2819
|
+
}
|
|
2820
|
+
return void 0;
|
|
2821
|
+
}
|
|
2822
|
+
if (typeof value !== "string") {
|
|
2823
|
+
throw new SessionArtifactValidationError(
|
|
2824
|
+
`${field} must be a string`,
|
|
2825
|
+
field
|
|
2826
|
+
);
|
|
2827
|
+
}
|
|
2828
|
+
const trimmed = value.trim();
|
|
2829
|
+
if (!trimmed) {
|
|
2830
|
+
if (required) {
|
|
2831
|
+
throw new SessionArtifactValidationError(`${field} is required`, field);
|
|
2832
|
+
}
|
|
2833
|
+
return void 0;
|
|
2834
|
+
}
|
|
2835
|
+
if (trimmed.length > maxLength) {
|
|
2836
|
+
throw new SessionArtifactValidationError(
|
|
2837
|
+
`${field} exceeds ${maxLength} characters`,
|
|
2838
|
+
field
|
|
2839
|
+
);
|
|
2840
|
+
}
|
|
2841
|
+
if (hasControlCharacter(trimmed, field === "description")) {
|
|
2842
|
+
throw new SessionArtifactValidationError(
|
|
2843
|
+
`${field} contains control characters`,
|
|
2844
|
+
field
|
|
2845
|
+
);
|
|
2846
|
+
}
|
|
2847
|
+
if (isDisplayField(field) && hasUnsafeDisplayPayload(trimmed)) {
|
|
2848
|
+
throw new SessionArtifactValidationError(
|
|
2849
|
+
`${field} contains unsafe markup`,
|
|
2850
|
+
field
|
|
2851
|
+
);
|
|
2852
|
+
}
|
|
2853
|
+
return trimmed;
|
|
2854
|
+
}
|
|
2855
|
+
__name(normalizeString, "normalizeString");
|
|
2856
|
+
function normalizeManagedId(value) {
|
|
2857
|
+
const managedId = normalizeString(value, "managedId", 200, false);
|
|
2858
|
+
if (!managedId) return void 0;
|
|
2859
|
+
if (managedId.includes("/") || managedId.includes("\\") || managedId.includes("..") || path2.isAbsolute(managedId) || path2.win32.isAbsolute(managedId)) {
|
|
2860
|
+
throw new SessionArtifactValidationError(
|
|
2861
|
+
"managedId must be an opaque managed resource id",
|
|
2862
|
+
"managedId"
|
|
2863
|
+
);
|
|
2864
|
+
}
|
|
2865
|
+
return managedId;
|
|
2866
|
+
}
|
|
2867
|
+
__name(normalizeManagedId, "normalizeManagedId");
|
|
2868
|
+
function isDisplayField(field) {
|
|
2869
|
+
return field === "title" || field === "description" || field === "mimeType" || field === "workspacePath" || field === "managedId";
|
|
2870
|
+
}
|
|
2871
|
+
__name(isDisplayField, "isDisplayField");
|
|
2872
|
+
function hasControlCharacter(value, allowLineWhitespace = false) {
|
|
2873
|
+
for (let i = 0; i < value.length; i++) {
|
|
2874
|
+
const code = value.charCodeAt(i);
|
|
2875
|
+
if (allowLineWhitespace && (code === 9 || code === 10 || code === 13)) {
|
|
2876
|
+
continue;
|
|
2877
|
+
}
|
|
2878
|
+
if (code <= 31 || code === 127 || code >= 8203 && code <= 8207 || code === 8232 || code === 8233 || code >= 8234 && code <= 8238 || code >= 8294 && code <= 8297 || code === 65279) {
|
|
2879
|
+
return true;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
return false;
|
|
2883
|
+
}
|
|
2884
|
+
__name(hasControlCharacter, "hasControlCharacter");
|
|
2885
|
+
function hasUnsafeDisplayPayload(value) {
|
|
2886
|
+
return /<\s*\/?[a-z!]|&(?:#[0-9]+|#x[0-9a-f]+|[a-z][a-z0-9]+);|javascript\s*:|data\s*:\s*(?:text\/(?:html|javascript)|application\/javascript|image\/svg\+xml)/i.test(
|
|
2887
|
+
value
|
|
2888
|
+
) || /(?:^|[\s"'`<])on[a-z][a-z0-9-]*\s*=/i.test(value);
|
|
2889
|
+
}
|
|
2890
|
+
__name(hasUnsafeDisplayPayload, "hasUnsafeDisplayPayload");
|
|
2891
|
+
function normalizeWorkspacePath(raw, workspaceCwd) {
|
|
2892
|
+
const trimmed = normalizeString(raw, "workspacePath", 500, true);
|
|
2893
|
+
if (path2.isAbsolute(trimmed)) {
|
|
2894
|
+
throw new SessionArtifactValidationError(
|
|
2895
|
+
"workspacePath must be relative to the workspace",
|
|
2896
|
+
"workspacePath"
|
|
2897
|
+
);
|
|
2898
|
+
}
|
|
2899
|
+
const absolute = path2.resolve(workspaceCwd, trimmed);
|
|
2900
|
+
const relative = path2.relative(workspaceCwd, absolute);
|
|
2901
|
+
if (!relative || isOutsidePath(relative)) {
|
|
2902
|
+
throw new SessionArtifactValidationError(
|
|
2903
|
+
"workspacePath must stay inside the workspace",
|
|
2904
|
+
"workspacePath"
|
|
2905
|
+
);
|
|
2906
|
+
}
|
|
2907
|
+
return relative.split(path2.sep).join("/");
|
|
2908
|
+
}
|
|
2909
|
+
__name(normalizeWorkspacePath, "normalizeWorkspacePath");
|
|
2910
|
+
function normalizeArtifactUrl(raw, allowFile) {
|
|
2911
|
+
const trimmed = normalizeString(raw, "url", 2048, true);
|
|
2912
|
+
let parsed;
|
|
2913
|
+
try {
|
|
2914
|
+
parsed = new URL(trimmed);
|
|
2915
|
+
} catch {
|
|
2916
|
+
throw new SessionArtifactValidationError("url must be valid", "url");
|
|
2917
|
+
}
|
|
2918
|
+
if (parsed.username || parsed.password) {
|
|
2919
|
+
throw new SessionArtifactValidationError(
|
|
2920
|
+
"url must not include credentials",
|
|
2921
|
+
"url"
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" && !(allowFile && parsed.protocol === "file:")) {
|
|
2925
|
+
throw new SessionArtifactValidationError(
|
|
2926
|
+
allowFile ? "url must use http, https, or file" : "url must use http or https",
|
|
2927
|
+
"url"
|
|
2928
|
+
);
|
|
2929
|
+
}
|
|
2930
|
+
return parsed.href;
|
|
2931
|
+
}
|
|
2932
|
+
__name(normalizeArtifactUrl, "normalizeArtifactUrl");
|
|
2933
|
+
function normalizeMetadata(metadata) {
|
|
2934
|
+
if (metadata === void 0) {
|
|
2935
|
+
return void 0;
|
|
2936
|
+
}
|
|
2937
|
+
if (typeof metadata !== "object" || metadata === null || Array.isArray(metadata)) {
|
|
2938
|
+
throw new SessionArtifactValidationError(
|
|
2939
|
+
"metadata must be an object",
|
|
2940
|
+
"metadata"
|
|
2941
|
+
);
|
|
2942
|
+
}
|
|
2943
|
+
const normalized = {};
|
|
2944
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
2945
|
+
if (!key) {
|
|
2946
|
+
throw new SessionArtifactValidationError(
|
|
2947
|
+
"metadata keys must not be empty",
|
|
2948
|
+
"metadata"
|
|
2949
|
+
);
|
|
2950
|
+
}
|
|
2951
|
+
if (key.length > 120) {
|
|
2952
|
+
throw new SessionArtifactValidationError(
|
|
2953
|
+
"metadata keys must be 120 characters or fewer",
|
|
2954
|
+
"metadata"
|
|
2955
|
+
);
|
|
2956
|
+
}
|
|
2957
|
+
if (hasControlCharacter(key) || hasUnsafeDisplayPayload(key)) {
|
|
2958
|
+
throw new SessionArtifactValidationError(
|
|
2959
|
+
"metadata keys contain unsafe content",
|
|
2960
|
+
"metadata"
|
|
2961
|
+
);
|
|
2962
|
+
}
|
|
2963
|
+
if (value !== null && typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
|
|
2964
|
+
throw new SessionArtifactValidationError(
|
|
2965
|
+
"metadata values must be primitive",
|
|
2966
|
+
"metadata"
|
|
2967
|
+
);
|
|
2968
|
+
}
|
|
2969
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
2970
|
+
throw new SessionArtifactValidationError(
|
|
2971
|
+
"metadata numbers must be finite",
|
|
2972
|
+
"metadata"
|
|
2973
|
+
);
|
|
2974
|
+
}
|
|
2975
|
+
if (typeof value === "string" && (hasControlCharacter(value) || hasUnsafeDisplayPayload(value))) {
|
|
2976
|
+
throw new SessionArtifactValidationError(
|
|
2977
|
+
"metadata string values contain unsafe content",
|
|
2978
|
+
"metadata"
|
|
2979
|
+
);
|
|
2980
|
+
}
|
|
2981
|
+
normalized[key] = value;
|
|
2982
|
+
}
|
|
2983
|
+
if (Object.keys(normalized).length === 0) {
|
|
2984
|
+
return void 0;
|
|
2985
|
+
}
|
|
2986
|
+
if (Buffer.byteLength(JSON.stringify(normalized), "utf8") > 4096) {
|
|
2987
|
+
throw new SessionArtifactValidationError(
|
|
2988
|
+
"metadata must be 4096 bytes or fewer",
|
|
2989
|
+
"metadata"
|
|
2990
|
+
);
|
|
2991
|
+
}
|
|
2992
|
+
return normalized;
|
|
2993
|
+
}
|
|
2994
|
+
__name(normalizeMetadata, "normalizeMetadata");
|
|
2995
|
+
function normalizeSizeBytes(value) {
|
|
2996
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
2997
|
+
throw new SessionArtifactValidationError(
|
|
2998
|
+
"sizeBytes must be a non-negative safe integer",
|
|
2999
|
+
"sizeBytes"
|
|
3000
|
+
);
|
|
3001
|
+
}
|
|
3002
|
+
return value;
|
|
3003
|
+
}
|
|
3004
|
+
__name(normalizeSizeBytes, "normalizeSizeBytes");
|
|
3005
|
+
function inferKind(input) {
|
|
3006
|
+
if (input.storage === "published") return "html";
|
|
3007
|
+
if (input.url) return "link";
|
|
3008
|
+
const ext = input.workspacePath ? path2.extname(input.workspacePath).toLowerCase() : "";
|
|
3009
|
+
if (ext === ".html" || ext === ".htm") return "html";
|
|
3010
|
+
if ([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"].includes(ext)) {
|
|
3011
|
+
return "image";
|
|
3012
|
+
}
|
|
3013
|
+
if ([".mp4", ".mov", ".webm"].includes(ext)) return "video";
|
|
3014
|
+
if ([".mp3", ".wav", ".m4a", ".ogg"].includes(ext)) return "audio";
|
|
3015
|
+
if (ext === ".pdf") return "pdf";
|
|
3016
|
+
if (ext === ".ipynb") return "notebook";
|
|
3017
|
+
return input.workspacePath ? "file" : "other";
|
|
3018
|
+
}
|
|
3019
|
+
__name(inferKind, "inferKind");
|
|
3020
|
+
async function getWorkspaceStatus(workspaceCwd, workspacePath, realWorkspaceCwd) {
|
|
3021
|
+
const absolutePath = path2.resolve(workspaceCwd, workspacePath);
|
|
3022
|
+
const realWorkspace = await realWorkspaceCwd;
|
|
3023
|
+
try {
|
|
3024
|
+
const realPath = await fs2.realpath(absolutePath);
|
|
3025
|
+
const relative = path2.relative(realWorkspace, realPath);
|
|
3026
|
+
if (!relative || isOutsidePath(relative)) {
|
|
3027
|
+
return { status: "missing", escaped: true };
|
|
3028
|
+
}
|
|
3029
|
+
const stat = await fs2.stat(realPath);
|
|
3030
|
+
return {
|
|
3031
|
+
status: "available",
|
|
3032
|
+
...stat.isFile() ? { sizeBytes: stat.size } : {}
|
|
3033
|
+
};
|
|
3034
|
+
} catch (error) {
|
|
3035
|
+
if (!isNotFoundError(error)) {
|
|
3036
|
+
throw error;
|
|
3037
|
+
}
|
|
3038
|
+
if (await danglingSymlinkEscapesWorkspace(absolutePath, realWorkspace)) {
|
|
3039
|
+
return { status: "missing", escaped: true };
|
|
3040
|
+
}
|
|
3041
|
+
return { status: "missing" };
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
__name(getWorkspaceStatus, "getWorkspaceStatus");
|
|
3045
|
+
async function danglingSymlinkEscapesWorkspace(absolutePath, realWorkspace) {
|
|
3046
|
+
try {
|
|
3047
|
+
const stat = await fs2.lstat(absolutePath);
|
|
3048
|
+
if (!stat.isSymbolicLink()) {
|
|
3049
|
+
return false;
|
|
3050
|
+
}
|
|
3051
|
+
const target = await fs2.readlink(absolutePath);
|
|
3052
|
+
const parent = await fs2.realpath(path2.dirname(absolutePath));
|
|
3053
|
+
const targetPath = path2.resolve(parent, target);
|
|
3054
|
+
return isOutsidePath(path2.relative(realWorkspace, targetPath));
|
|
3055
|
+
} catch (error) {
|
|
3056
|
+
if (isNotFoundError(error)) {
|
|
3057
|
+
return false;
|
|
3058
|
+
}
|
|
3059
|
+
throw error;
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
__name(danglingSymlinkEscapesWorkspace, "danglingSymlinkEscapesWorkspace");
|
|
3063
|
+
async function runInBatches(items, batchSize, fn) {
|
|
3064
|
+
for (let index = 0; index < items.length; index += batchSize) {
|
|
3065
|
+
await Promise.all(items.slice(index, index + batchSize).map(fn));
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
__name(runInBatches, "runInBatches");
|
|
3069
|
+
function isNotFoundError(error) {
|
|
3070
|
+
if (typeof error !== "object" || error === null || !("code" in error)) {
|
|
3071
|
+
return false;
|
|
3072
|
+
}
|
|
3073
|
+
const code = error.code;
|
|
3074
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
3075
|
+
}
|
|
3076
|
+
__name(isNotFoundError, "isNotFoundError");
|
|
3077
|
+
function isOutsidePath(relative) {
|
|
3078
|
+
return relative === ".." || relative.startsWith(`..${path2.sep}`) || path2.isAbsolute(relative);
|
|
3079
|
+
}
|
|
3080
|
+
__name(isOutsidePath, "isOutsidePath");
|
|
3081
|
+
|
|
1861
3082
|
// packages/acp-bridge/src/bridge.ts
|
|
1862
3083
|
var NOOP_BRIDGE_TELEMETRY = {
|
|
1863
3084
|
captureContext: /* @__PURE__ */ __name(() => void 0, "captureContext"),
|
|
@@ -1884,6 +3105,95 @@ var NOOP_BRIDGE_TELEMETRY = {
|
|
|
1884
3105
|
return { ...request, _meta: nextMeta };
|
|
1885
3106
|
}
|
|
1886
3107
|
};
|
|
3108
|
+
var KNOWN_SESSION_UPDATE_TYPES = /* @__PURE__ */ new Set([
|
|
3109
|
+
"user_message_chunk",
|
|
3110
|
+
"agent_message_chunk",
|
|
3111
|
+
"agent_thought_chunk",
|
|
3112
|
+
"tool_call",
|
|
3113
|
+
"tool_call_update",
|
|
3114
|
+
"plan",
|
|
3115
|
+
"available_commands_update",
|
|
3116
|
+
"current_mode_update",
|
|
3117
|
+
"config_option_update",
|
|
3118
|
+
"session_info_update",
|
|
3119
|
+
"usage_update"
|
|
3120
|
+
]);
|
|
3121
|
+
var MAX_BULK_REPLAY_UPDATES = 1e4;
|
|
3122
|
+
function isRecord2(value) {
|
|
3123
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3124
|
+
}
|
|
3125
|
+
__name(isRecord2, "isRecord");
|
|
3126
|
+
function isBulkReplayUpdate(value) {
|
|
3127
|
+
if (!isRecord2(value)) return false;
|
|
3128
|
+
const updateType = value["sessionUpdate"];
|
|
3129
|
+
return typeof updateType === "string" && KNOWN_SESSION_UPDATE_TYPES.has(updateType);
|
|
3130
|
+
}
|
|
3131
|
+
__name(isBulkReplayUpdate, "isBulkReplayUpdate");
|
|
3132
|
+
function describeLoadReplayValue(value) {
|
|
3133
|
+
if (Array.isArray(value)) return "array";
|
|
3134
|
+
if (value === null) return "null";
|
|
3135
|
+
return typeof value;
|
|
3136
|
+
}
|
|
3137
|
+
__name(describeLoadReplayValue, "describeLoadReplayValue");
|
|
3138
|
+
function extractLoadReplayResponse(state) {
|
|
3139
|
+
const meta = isRecord2(state._meta) ? state._meta : void 0;
|
|
3140
|
+
const replay = meta?.[LOAD_REPLAY_META_KEY];
|
|
3141
|
+
if (replay === void 0) return { state, updates: [] };
|
|
3142
|
+
if (!isRecord2(replay) || replay["v"] !== LOAD_REPLAY_VERSION) {
|
|
3143
|
+
const version = isRecord2(replay) ? replay["v"] : void 0;
|
|
3144
|
+
throw new Error(
|
|
3145
|
+
`Invalid qwen.session.loadReplay payload (type=${describeLoadReplayValue(replay)}, version=${JSON.stringify(version)})`
|
|
3146
|
+
);
|
|
3147
|
+
}
|
|
3148
|
+
const rawUpdates = replay["updates"];
|
|
3149
|
+
if (!Array.isArray(rawUpdates)) {
|
|
3150
|
+
throw new Error(
|
|
3151
|
+
`Invalid qwen.session.loadReplay updates (version=${LOAD_REPLAY_VERSION}, count=not-array)`
|
|
3152
|
+
);
|
|
3153
|
+
}
|
|
3154
|
+
if (rawUpdates.length > MAX_BULK_REPLAY_UPDATES) {
|
|
3155
|
+
throw new Error(
|
|
3156
|
+
`qwen.session.loadReplay updates exceed limit (${rawUpdates.length} > ${MAX_BULK_REPLAY_UPDATES})`
|
|
3157
|
+
);
|
|
3158
|
+
}
|
|
3159
|
+
const partial = replay["partial"];
|
|
3160
|
+
if (partial !== void 0 && partial !== true) {
|
|
3161
|
+
throw new Error(
|
|
3162
|
+
`Invalid qwen.session.loadReplay partial (version=${LOAD_REPLAY_VERSION}, partial=${JSON.stringify(partial)})`
|
|
3163
|
+
);
|
|
3164
|
+
}
|
|
3165
|
+
const replayError = replay["replayError"];
|
|
3166
|
+
if (replayError !== void 0 && typeof replayError !== "string") {
|
|
3167
|
+
throw new Error(
|
|
3168
|
+
`Invalid qwen.session.loadReplay replayError (version=${LOAD_REPLAY_VERSION}, replayError=${describeLoadReplayValue(replayError)})`
|
|
3169
|
+
);
|
|
3170
|
+
}
|
|
3171
|
+
const invalidUpdateIndex = rawUpdates.findIndex(
|
|
3172
|
+
(update) => !isBulkReplayUpdate(update)
|
|
3173
|
+
);
|
|
3174
|
+
if (invalidUpdateIndex !== -1) {
|
|
3175
|
+
const invalidUpdate = rawUpdates[invalidUpdateIndex];
|
|
3176
|
+
const discriminator = isRecord2(invalidUpdate) ? invalidUpdate["sessionUpdate"] : void 0;
|
|
3177
|
+
throw new Error(
|
|
3178
|
+
`Invalid qwen.session.loadReplay update at index ${invalidUpdateIndex} (version=${LOAD_REPLAY_VERSION}, count=${rawUpdates.length}, sessionUpdate=${JSON.stringify(discriminator)})`
|
|
3179
|
+
);
|
|
3180
|
+
}
|
|
3181
|
+
const nextMeta = { ...meta ?? {} };
|
|
3182
|
+
delete nextMeta[LOAD_REPLAY_META_KEY];
|
|
3183
|
+
const cleanState = { ...state };
|
|
3184
|
+
if (Object.keys(nextMeta).length > 0) {
|
|
3185
|
+
cleanState._meta = nextMeta;
|
|
3186
|
+
} else {
|
|
3187
|
+
delete cleanState._meta;
|
|
3188
|
+
}
|
|
3189
|
+
return {
|
|
3190
|
+
state: cleanState,
|
|
3191
|
+
updates: rawUpdates,
|
|
3192
|
+
...partial === true ? { partial: true } : {},
|
|
3193
|
+
...typeof replayError === "string" ? { replayError } : {}
|
|
3194
|
+
};
|
|
3195
|
+
}
|
|
3196
|
+
__name(extractLoadReplayResponse, "extractLoadReplayResponse");
|
|
1887
3197
|
function isServeDebugLoggingEnabled() {
|
|
1888
3198
|
const value = process.env["QWEN_SERVE_DEBUG"];
|
|
1889
3199
|
if (!value) return false;
|
|
@@ -1927,6 +3237,62 @@ function parseWorkspaceMemoryRememberResult(response) {
|
|
|
1927
3237
|
};
|
|
1928
3238
|
}
|
|
1929
3239
|
__name(parseWorkspaceMemoryRememberResult, "parseWorkspaceMemoryRememberResult");
|
|
3240
|
+
function isBridgeAutoMemoryTopic(value) {
|
|
3241
|
+
return value === "user" || value === "feedback" || value === "project" || value === "reference";
|
|
3242
|
+
}
|
|
3243
|
+
__name(isBridgeAutoMemoryTopic, "isBridgeAutoMemoryTopic");
|
|
3244
|
+
function parseWorkspaceMemoryForgetMatch(value) {
|
|
3245
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3246
|
+
return null;
|
|
3247
|
+
}
|
|
3248
|
+
const record = value;
|
|
3249
|
+
if (!isBridgeAutoMemoryTopic(record["topic"]) || typeof record["summary"] !== "string" || typeof record["filePath"] !== "string") {
|
|
3250
|
+
return null;
|
|
3251
|
+
}
|
|
3252
|
+
return {
|
|
3253
|
+
topic: record["topic"],
|
|
3254
|
+
summary: record["summary"],
|
|
3255
|
+
filePath: record["filePath"]
|
|
3256
|
+
};
|
|
3257
|
+
}
|
|
3258
|
+
__name(parseWorkspaceMemoryForgetMatch, "parseWorkspaceMemoryForgetMatch");
|
|
3259
|
+
function parseWorkspaceMemoryForgetResult(response) {
|
|
3260
|
+
if (response === null || typeof response !== "object" || Array.isArray(response)) {
|
|
3261
|
+
throw new Error("Malformed workspace memory forget response");
|
|
3262
|
+
}
|
|
3263
|
+
const record = response;
|
|
3264
|
+
const summary = record["summary"];
|
|
3265
|
+
const removedEntries = record["removedEntries"];
|
|
3266
|
+
const touchedTopics = record["touchedTopics"];
|
|
3267
|
+
const parsedRemovedEntries = Array.isArray(removedEntries) ? removedEntries.map(parseWorkspaceMemoryForgetMatch) : [];
|
|
3268
|
+
if (summary !== void 0 && typeof summary !== "string" || !Array.isArray(removedEntries) || parsedRemovedEntries.some((entry) => entry === null) || !Array.isArray(touchedTopics) || !touchedTopics.every(isBridgeAutoMemoryTopic)) {
|
|
3269
|
+
throw new Error("Malformed workspace memory forget response");
|
|
3270
|
+
}
|
|
3271
|
+
return {
|
|
3272
|
+
...summary === void 0 ? {} : { summary },
|
|
3273
|
+
removedEntries: parsedRemovedEntries,
|
|
3274
|
+
touchedTopics
|
|
3275
|
+
};
|
|
3276
|
+
}
|
|
3277
|
+
__name(parseWorkspaceMemoryForgetResult, "parseWorkspaceMemoryForgetResult");
|
|
3278
|
+
function parseWorkspaceMemoryDreamResult(response) {
|
|
3279
|
+
if (response === null || typeof response !== "object" || Array.isArray(response)) {
|
|
3280
|
+
throw new Error("Malformed workspace memory dream response");
|
|
3281
|
+
}
|
|
3282
|
+
const record = response;
|
|
3283
|
+
const summary = record["summary"];
|
|
3284
|
+
const touchedTopics = record["touchedTopics"];
|
|
3285
|
+
const dedupedEntries = record["dedupedEntries"];
|
|
3286
|
+
if (summary !== void 0 && typeof summary !== "string" || !Array.isArray(touchedTopics) || !touchedTopics.every(isBridgeAutoMemoryTopic) || typeof dedupedEntries !== "number" || !Number.isFinite(dedupedEntries)) {
|
|
3287
|
+
throw new Error("Malformed workspace memory dream response");
|
|
3288
|
+
}
|
|
3289
|
+
return {
|
|
3290
|
+
...summary === void 0 ? {} : { summary },
|
|
3291
|
+
touchedTopics,
|
|
3292
|
+
dedupedEntries
|
|
3293
|
+
};
|
|
3294
|
+
}
|
|
3295
|
+
__name(parseWorkspaceMemoryDreamResult, "parseWorkspaceMemoryDreamResult");
|
|
1930
3296
|
function echoPromptToSessionBus(entry, req, originatorClientId) {
|
|
1931
3297
|
const prompt = req.prompt;
|
|
1932
3298
|
if (!Array.isArray(prompt) || prompt.length === 0) return;
|
|
@@ -2050,7 +3416,7 @@ function broadcastTurnError(entry, sessionId, err, promptId, originatorClientId)
|
|
|
2050
3416
|
}
|
|
2051
3417
|
}
|
|
2052
3418
|
__name(broadcastTurnError, "broadcastTurnError");
|
|
2053
|
-
function
|
|
3419
|
+
function hasControlCharacter2(value) {
|
|
2054
3420
|
for (let i = 0; i < value.length; i += 1) {
|
|
2055
3421
|
const code = value.charCodeAt(i);
|
|
2056
3422
|
if (code <= 31 || code === 127) {
|
|
@@ -2059,7 +3425,7 @@ function hasControlCharacter(value) {
|
|
|
2059
3425
|
}
|
|
2060
3426
|
return false;
|
|
2061
3427
|
}
|
|
2062
|
-
__name(
|
|
3428
|
+
__name(hasControlCharacter2, "hasControlCharacter");
|
|
2063
3429
|
function extractPromptText(prompt) {
|
|
2064
3430
|
if (!Array.isArray(prompt)) return "";
|
|
2065
3431
|
let hasImage = false;
|
|
@@ -2152,7 +3518,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2152
3518
|
} else {
|
|
2153
3519
|
maxPendingPromptsPerSession = maxPendingPromptsRaw;
|
|
2154
3520
|
}
|
|
2155
|
-
if (!
|
|
3521
|
+
if (!path3.isAbsolute(opts.boundWorkspace)) {
|
|
2156
3522
|
throw new TypeError(
|
|
2157
3523
|
`Invalid boundWorkspace: "${opts.boundWorkspace}". Must be an absolute path.`
|
|
2158
3524
|
);
|
|
@@ -2378,6 +3744,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2378
3744
|
},
|
|
2379
3745
|
async () => await channelFactory(boundWorkspace, childEnvOverrides)
|
|
2380
3746
|
);
|
|
3747
|
+
const sessionIds = /* @__PURE__ */ new Set();
|
|
2381
3748
|
const client = new BridgeClient(
|
|
2382
3749
|
// BfFut: ACP today carries a sessionId on every per-session
|
|
2383
3750
|
// notification / request, so the no-sessionId branch is
|
|
@@ -2427,14 +3794,15 @@ function createAcpSessionBridge(opts) {
|
|
|
2427
3794
|
// the per-WS-connection `ClientMcpRegistrar`. Omitted callers (tests,
|
|
2428
3795
|
// Mode A) never host a client MCP server, so the method stays
|
|
2429
3796
|
// unreachable.
|
|
2430
|
-
opts.clientMcpSender
|
|
3797
|
+
opts.clientMcpSender,
|
|
3798
|
+
(sessionId) => sessionIds.has(sessionId)
|
|
2431
3799
|
);
|
|
2432
3800
|
const connection = new ClientSideConnection(() => client, channel.stream);
|
|
2433
3801
|
const info = {
|
|
2434
3802
|
channel,
|
|
2435
3803
|
connection,
|
|
2436
3804
|
client,
|
|
2437
|
-
sessionIds
|
|
3805
|
+
sessionIds,
|
|
2438
3806
|
pendingRestoreIds: /* @__PURE__ */ new Set(),
|
|
2439
3807
|
sessionSpawnsInFlight: 0,
|
|
2440
3808
|
workspaceControlInFlight: 0,
|
|
@@ -2685,7 +4053,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2685
4053
|
return entry.transportClosedReject;
|
|
2686
4054
|
}, "getTransportClosedReject");
|
|
2687
4055
|
const resolveWorkspaceKey = /* @__PURE__ */ __name((workspaceCwd) => {
|
|
2688
|
-
if (!
|
|
4056
|
+
if (!path3.isAbsolute(workspaceCwd)) {
|
|
2689
4057
|
throw new Error(
|
|
2690
4058
|
`workspaceCwd must be an absolute path; got "${workspaceCwd}"`
|
|
2691
4059
|
);
|
|
@@ -2902,7 +4270,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2902
4270
|
if (rerun) void reconcileAfterRoundtrip(entry, target);
|
|
2903
4271
|
}
|
|
2904
4272
|
}, "reconcileAfterRoundtrip");
|
|
2905
|
-
const createSessionEntry = /* @__PURE__ */ __name((ci, sessionId, workspaceCwd, events = createSessionEventBus()) => {
|
|
4273
|
+
const createSessionEntry = /* @__PURE__ */ __name((ci, sessionId, workspaceCwd, events = createSessionEventBus(), options = {}) => {
|
|
2906
4274
|
const entry = {
|
|
2907
4275
|
sessionId,
|
|
2908
4276
|
workspaceCwd,
|
|
@@ -2910,6 +4278,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2910
4278
|
channel: ci.channel,
|
|
2911
4279
|
connection: ci.connection,
|
|
2912
4280
|
events,
|
|
4281
|
+
artifacts: new SessionArtifactStore({ sessionId, workspaceCwd }),
|
|
2913
4282
|
promptQueue: Promise.resolve(),
|
|
2914
4283
|
pendingPromptCount: 0,
|
|
2915
4284
|
pendingPromptList: [],
|
|
@@ -2930,9 +4299,39 @@ function createAcpSessionBridge(opts) {
|
|
|
2930
4299
|
byId.set(entry.sessionId, entry);
|
|
2931
4300
|
touchActivity();
|
|
2932
4301
|
telemetry.metrics?.sessionLifecycle("spawn");
|
|
2933
|
-
|
|
4302
|
+
if (options.drainEarlyEvents !== false) {
|
|
4303
|
+
ci.client.drainEarlyEvents(entry.sessionId, entry);
|
|
4304
|
+
}
|
|
2934
4305
|
return entry;
|
|
2935
4306
|
}, "createSessionEntry");
|
|
4307
|
+
const publishArtifactChanges = /* @__PURE__ */ __name((entry, changes, originatorClientId) => {
|
|
4308
|
+
for (const change of changes) {
|
|
4309
|
+
entry.events.publish({
|
|
4310
|
+
type: "artifact_changed",
|
|
4311
|
+
data: { sessionId: entry.sessionId, change },
|
|
4312
|
+
...originatorClientId ? { originatorClientId } : {}
|
|
4313
|
+
});
|
|
4314
|
+
}
|
|
4315
|
+
}, "publishArtifactChanges");
|
|
4316
|
+
const makeClientArtifactInput = /* @__PURE__ */ __name((artifact, clientId) => {
|
|
4317
|
+
const input = {
|
|
4318
|
+
title: artifact.title,
|
|
4319
|
+
kind: artifact.kind,
|
|
4320
|
+
storage: artifact.storage,
|
|
4321
|
+
description: artifact.description,
|
|
4322
|
+
workspacePath: artifact.workspacePath,
|
|
4323
|
+
managedId: artifact.managedId,
|
|
4324
|
+
url: artifact.url,
|
|
4325
|
+
mimeType: artifact.mimeType,
|
|
4326
|
+
sizeBytes: artifact.sizeBytes,
|
|
4327
|
+
metadata: artifact.metadata,
|
|
4328
|
+
source: "client"
|
|
4329
|
+
};
|
|
4330
|
+
if (clientId) {
|
|
4331
|
+
input.clientId = clientId;
|
|
4332
|
+
}
|
|
4333
|
+
return input;
|
|
4334
|
+
}, "makeClientArtifactInput");
|
|
2936
4335
|
const seedSnapshotCaches = /* @__PURE__ */ __name((entry, resp) => {
|
|
2937
4336
|
const model = resp.models?.currentModelId;
|
|
2938
4337
|
if (typeof model === "string" && model.length > 0) {
|
|
@@ -2962,22 +4361,30 @@ function createAcpSessionBridge(opts) {
|
|
|
2962
4361
|
return typeof maybe.message === "string" && maybe.message === `Resource not found: ${expectedUri}`;
|
|
2963
4362
|
}, "isAcpSessionResourceNotFound");
|
|
2964
4363
|
const replayFieldsFor = /* @__PURE__ */ __name((entry, action) => {
|
|
4364
|
+
const replayStatus = action === "load" && entry.restoreReplayPartial === true ? {
|
|
4365
|
+
partial: true,
|
|
4366
|
+
...typeof entry.restoreReplayError === "string" ? { replayError: entry.restoreReplayError } : {}
|
|
4367
|
+
} : {};
|
|
2965
4368
|
const snapshot = entry.events.snapshotReplay();
|
|
2966
|
-
if (!snapshot)
|
|
4369
|
+
if (!snapshot) {
|
|
4370
|
+
return { lastEventId: entry.events.lastEventId, ...replayStatus };
|
|
4371
|
+
}
|
|
2967
4372
|
if (action === "load") {
|
|
2968
4373
|
return {
|
|
2969
4374
|
compactedReplay: snapshot.compactedTurns,
|
|
2970
4375
|
liveJournal: snapshot.liveJournal,
|
|
2971
|
-
lastEventId: snapshot.lastEventId
|
|
4376
|
+
lastEventId: snapshot.lastEventId,
|
|
4377
|
+
...replayStatus
|
|
2972
4378
|
};
|
|
2973
4379
|
}
|
|
2974
|
-
return { lastEventId: snapshot.lastEventId };
|
|
4380
|
+
return { lastEventId: snapshot.lastEventId, ...replayStatus };
|
|
2975
4381
|
}, "replayFieldsFor");
|
|
2976
4382
|
async function restoreSession(action, req) {
|
|
2977
4383
|
if (shuttingDown) {
|
|
2978
4384
|
throw new Error("AcpSessionBridge is shutting down");
|
|
2979
4385
|
}
|
|
2980
4386
|
const workspaceKey = resolveWorkspaceKey(req.workspaceCwd);
|
|
4387
|
+
const historyReplay = action === "load" ? req.historyReplay ?? "stream" : "stream";
|
|
2981
4388
|
const existing = byId.get(req.sessionId);
|
|
2982
4389
|
if (existing) {
|
|
2983
4390
|
existing.attachCount++;
|
|
@@ -2997,7 +4404,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2997
4404
|
}
|
|
2998
4405
|
const inFlight = inFlightRestores.get(req.sessionId);
|
|
2999
4406
|
if (inFlight) {
|
|
3000
|
-
if (action !== inFlight.action) {
|
|
4407
|
+
if (action !== inFlight.action || historyReplay !== inFlight.historyReplay) {
|
|
3001
4408
|
throw new RestoreInProgressError(
|
|
3002
4409
|
req.sessionId,
|
|
3003
4410
|
inFlight.action,
|
|
@@ -3046,6 +4453,9 @@ function createAcpSessionBridge(opts) {
|
|
|
3046
4453
|
transportClosed.catch(() => {
|
|
3047
4454
|
});
|
|
3048
4455
|
let state;
|
|
4456
|
+
let replayUpdates = [];
|
|
4457
|
+
let replayPartial;
|
|
4458
|
+
let replayError;
|
|
3049
4459
|
try {
|
|
3050
4460
|
if (action === "load") {
|
|
3051
4461
|
state = await Promise.race([
|
|
@@ -3058,7 +4468,12 @@ function createAcpSessionBridge(opts) {
|
|
|
3058
4468
|
// the agent side. The SDK's `RestoreSessionRequest`
|
|
3059
4469
|
// intentionally has no `mcpServers` field for the
|
|
3060
4470
|
// same reason.
|
|
3061
|
-
mcpServers: []
|
|
4471
|
+
mcpServers: [],
|
|
4472
|
+
...historyReplay === "response" ? {
|
|
4473
|
+
_meta: {
|
|
4474
|
+
[LOAD_REPLAY_MODE_META_KEY]: LOAD_REPLAY_BULK_MODE
|
|
4475
|
+
}
|
|
4476
|
+
} : {}
|
|
3062
4477
|
}),
|
|
3063
4478
|
initTimeoutMs,
|
|
3064
4479
|
"loadSession"
|
|
@@ -3079,6 +4494,13 @@ function createAcpSessionBridge(opts) {
|
|
|
3079
4494
|
transportClosed
|
|
3080
4495
|
]);
|
|
3081
4496
|
}
|
|
4497
|
+
if (action === "load" && historyReplay === "response") {
|
|
4498
|
+
const extracted = extractLoadReplayResponse(state);
|
|
4499
|
+
state = extracted.state;
|
|
4500
|
+
replayUpdates = extracted.updates;
|
|
4501
|
+
replayPartial = extracted.partial;
|
|
4502
|
+
replayError = extracted.replayError;
|
|
4503
|
+
}
|
|
3082
4504
|
} catch (err) {
|
|
3083
4505
|
restoreEvents.close();
|
|
3084
4506
|
if (isAcpSessionResourceNotFound(err, req.sessionId)) {
|
|
@@ -3122,10 +4544,21 @@ function createAcpSessionBridge(opts) {
|
|
|
3122
4544
|
ci,
|
|
3123
4545
|
req.sessionId,
|
|
3124
4546
|
workspaceKey,
|
|
3125
|
-
restoreEvents
|
|
4547
|
+
restoreEvents,
|
|
4548
|
+
{ drainEarlyEvents: replayUpdates.length === 0 }
|
|
3126
4549
|
);
|
|
3127
4550
|
entry.restoreState = state;
|
|
4551
|
+
if (replayPartial === true) {
|
|
4552
|
+
entry.restoreReplayPartial = true;
|
|
4553
|
+
}
|
|
4554
|
+
if (replayError !== void 0) {
|
|
4555
|
+
entry.restoreReplayError = replayError;
|
|
4556
|
+
}
|
|
3128
4557
|
seedSnapshotCaches(entry, state);
|
|
4558
|
+
if (replayUpdates.length > 0) {
|
|
4559
|
+
await ci.client.seedSessionUpdates(entry, replayUpdates);
|
|
4560
|
+
ci.client.drainEarlyEvents(entry.sessionId, entry);
|
|
4561
|
+
}
|
|
3129
4562
|
const clientId = registerClient(entry, req.clientId);
|
|
3130
4563
|
entry.attachCount = coalesceState.count;
|
|
3131
4564
|
registeredEntry = entry;
|
|
@@ -3145,13 +4578,28 @@ function createAcpSessionBridge(opts) {
|
|
|
3145
4578
|
pendingRestoreEvents.delete(req.sessionId);
|
|
3146
4579
|
if (!registeredEntry) {
|
|
3147
4580
|
restoreEvents.close();
|
|
4581
|
+
let removedRestoreEntry = false;
|
|
4582
|
+
if (byId.get(req.sessionId)?.events === restoreEvents) {
|
|
4583
|
+
byId.delete(req.sessionId);
|
|
4584
|
+
ci?.sessionIds.delete(req.sessionId);
|
|
4585
|
+
removedRestoreEntry = true;
|
|
4586
|
+
}
|
|
4587
|
+
if (removedRestoreEntry && ci && hasNoChannelWork(ci)) {
|
|
4588
|
+
ci.emptyReapPending = true;
|
|
4589
|
+
ci.isDying = true;
|
|
4590
|
+
}
|
|
3148
4591
|
ci?.client.markSessionClosed(req.sessionId);
|
|
3149
4592
|
}
|
|
3150
4593
|
if (ci) {
|
|
3151
4594
|
await reapPendingEmptyChannel(ci);
|
|
3152
4595
|
}
|
|
3153
4596
|
});
|
|
3154
|
-
inFlightRestores.set(req.sessionId, {
|
|
4597
|
+
inFlightRestores.set(req.sessionId, {
|
|
4598
|
+
action,
|
|
4599
|
+
historyReplay,
|
|
4600
|
+
promise,
|
|
4601
|
+
coalesceState
|
|
4602
|
+
});
|
|
3155
4603
|
try {
|
|
3156
4604
|
return await promise;
|
|
3157
4605
|
} finally {
|
|
@@ -3736,6 +5184,11 @@ function createAcpSessionBridge(opts) {
|
|
|
3736
5184
|
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
3737
5185
|
return entry.events.lastEventId;
|
|
3738
5186
|
},
|
|
5187
|
+
getSessionReplaySnapshot(sessionId) {
|
|
5188
|
+
const entry = byId.get(sessionId);
|
|
5189
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
5190
|
+
return entry.events.snapshotReplay();
|
|
5191
|
+
},
|
|
3739
5192
|
respondToPermission(requestId, response, context) {
|
|
3740
5193
|
const sessionId = permissionMediator.peekSessionFor(requestId);
|
|
3741
5194
|
if (sessionId === void 0 || !byId.has(sessionId)) {
|
|
@@ -3957,7 +5410,7 @@ function createAcpSessionBridge(opts) {
|
|
|
3957
5410
|
`must be a string of at most ${MAX_DISPLAY_NAME_LENGTH} characters`
|
|
3958
5411
|
);
|
|
3959
5412
|
}
|
|
3960
|
-
if (
|
|
5413
|
+
if (hasControlCharacter2(metadata.displayName)) {
|
|
3961
5414
|
throw new InvalidSessionMetadataError(
|
|
3962
5415
|
"displayName",
|
|
3963
5416
|
"must not contain control characters"
|
|
@@ -3999,8 +5452,30 @@ function createAcpSessionBridge(opts) {
|
|
|
3999
5452
|
}
|
|
4000
5453
|
return { displayName: entry.displayName };
|
|
4001
5454
|
},
|
|
5455
|
+
async getSessionArtifacts(sessionId) {
|
|
5456
|
+
const entry = byId.get(sessionId);
|
|
5457
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
5458
|
+
return entry.artifacts.list();
|
|
5459
|
+
},
|
|
5460
|
+
async addSessionArtifact(sessionId, artifact, context) {
|
|
5461
|
+
const entry = byId.get(sessionId);
|
|
5462
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
5463
|
+
const clientId = resolveTrustedClientId(entry, context?.clientId);
|
|
5464
|
+
const input = makeClientArtifactInput(artifact, clientId);
|
|
5465
|
+
const result = await entry.artifacts.upsertMany([input], { strict: true });
|
|
5466
|
+
publishArtifactChanges(entry, result.changes, clientId);
|
|
5467
|
+
return result;
|
|
5468
|
+
},
|
|
5469
|
+
async removeSessionArtifact(sessionId, artifactId, context) {
|
|
5470
|
+
const entry = byId.get(sessionId);
|
|
5471
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
5472
|
+
const clientId = resolveTrustedClientId(entry, context?.clientId);
|
|
5473
|
+
const result = await entry.artifacts.remove(artifactId, { clientId });
|
|
5474
|
+
publishArtifactChanges(entry, result.changes, clientId);
|
|
5475
|
+
return result;
|
|
5476
|
+
},
|
|
4002
5477
|
listWorkspaceSessions(workspaceCwd) {
|
|
4003
|
-
if (!
|
|
5478
|
+
if (!path3.isAbsolute(workspaceCwd)) return [];
|
|
4004
5479
|
const key = workspaceCwd === boundWorkspace ? boundWorkspace : canonicalizeWorkspace(workspaceCwd);
|
|
4005
5480
|
if (key !== boundWorkspace) return [];
|
|
4006
5481
|
const out = [];
|
|
@@ -4142,6 +5617,54 @@ function createAcpSessionBridge(opts) {
|
|
|
4142
5617
|
}
|
|
4143
5618
|
}
|
|
4144
5619
|
},
|
|
5620
|
+
async runWorkspaceMemoryForget(request) {
|
|
5621
|
+
const info = await ensureChannel();
|
|
5622
|
+
try {
|
|
5623
|
+
const response = await withWorkspaceControl(
|
|
5624
|
+
info,
|
|
5625
|
+
() => withTimeout(
|
|
5626
|
+
Promise.race([
|
|
5627
|
+
info.connection.extMethod(
|
|
5628
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryForget,
|
|
5629
|
+
{ ...request, cwd: boundWorkspace }
|
|
5630
|
+
),
|
|
5631
|
+
getChannelClosedReject(info)
|
|
5632
|
+
]),
|
|
5633
|
+
WORKSPACE_MEMORY_REMEMBER_TIMEOUT_MS,
|
|
5634
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryForget
|
|
5635
|
+
)
|
|
5636
|
+
);
|
|
5637
|
+
return parseWorkspaceMemoryForgetResult(response);
|
|
5638
|
+
} finally {
|
|
5639
|
+
if (hasNoChannelWork(info)) {
|
|
5640
|
+
await startIdleTimer(info, "workspace memory forget");
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5643
|
+
},
|
|
5644
|
+
async runWorkspaceMemoryDream() {
|
|
5645
|
+
const info = await ensureChannel();
|
|
5646
|
+
try {
|
|
5647
|
+
const response = await withWorkspaceControl(
|
|
5648
|
+
info,
|
|
5649
|
+
() => withTimeout(
|
|
5650
|
+
Promise.race([
|
|
5651
|
+
info.connection.extMethod(
|
|
5652
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryDream,
|
|
5653
|
+
{ cwd: boundWorkspace }
|
|
5654
|
+
),
|
|
5655
|
+
getChannelClosedReject(info)
|
|
5656
|
+
]),
|
|
5657
|
+
WORKSPACE_MEMORY_REMEMBER_TIMEOUT_MS,
|
|
5658
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryDream
|
|
5659
|
+
)
|
|
5660
|
+
);
|
|
5661
|
+
return parseWorkspaceMemoryDreamResult(response);
|
|
5662
|
+
} finally {
|
|
5663
|
+
if (hasNoChannelWork(info)) {
|
|
5664
|
+
await startIdleTimer(info, "workspace memory dream");
|
|
5665
|
+
}
|
|
5666
|
+
}
|
|
5667
|
+
},
|
|
4145
5668
|
async getWorkspaceMcpToolsStatus(serverName) {
|
|
4146
5669
|
return requestWorkspaceStatus(
|
|
4147
5670
|
SERVE_STATUS_EXT_METHODS.workspaceMcpTools,
|
|
@@ -5214,6 +6737,7 @@ __name(withTimeout, "withTimeout");
|
|
|
5214
6737
|
var createHttpAcpBridge = createAcpSessionBridge;
|
|
5215
6738
|
|
|
5216
6739
|
export {
|
|
6740
|
+
SessionArtifactValidationError,
|
|
5217
6741
|
extractErrorMessage,
|
|
5218
6742
|
extractErrorCode,
|
|
5219
6743
|
createAcpSessionBridge,
|
|
@@ -5224,3 +6748,8 @@ export {
|
|
|
5224
6748
|
* Copyright 2025 Qwen Team
|
|
5225
6749
|
* SPDX-License-Identifier: Apache-2.0
|
|
5226
6750
|
*/
|
|
6751
|
+
/**
|
|
6752
|
+
* @license
|
|
6753
|
+
* Copyright 2026 Qwen Team
|
|
6754
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
6755
|
+
*/
|