@qwen-code/qwen-code 0.19.5 → 0.19.6
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 +9 -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/chunks/{MaxSizedBox-5JV77KRA.js → MaxSizedBox-SK7CUWZQ.js} +14 -14
- package/chunks/{StandaloneSessionPicker-MGUGB6PH.js → StandaloneSessionPicker-G44HGSAP.js} +25 -25
- package/chunks/{acpAgent-4F36XM3X.js → acpAgent-PKCTYWJV.js} +346 -131
- package/chunks/{agent-IWBUZI6A.js → agent-IYMHUXWB.js} +11 -11
- package/chunks/{agent-headless-JUTICAYO.js → agent-headless-L2DAW6I5.js} +11 -11
- package/chunks/{anthropicContentGenerator-WL3LJOUB.js → anthropicContentGenerator-H5ZOEENQ.js} +2 -2
- package/chunks/{artifact-tool-W76WC2JX.js → artifact-tool-SLYPWG3C.js} +15 -2
- package/chunks/{askUserQuestion-J3P6TH3V.js → askUserQuestion-OKPTECON.js} +1 -1
- package/chunks/{bridge-DHZHQ4UV.js → bridge-DF3IJQ5V.js} +17 -16
- package/chunks/{channel-worker-supervisor-EVPAYNZ5.js → channel-worker-supervisor-JUYQ5Z4R.js} +5 -5
- package/chunks/chunk-2INJBYLJ.js +949 -0
- package/chunks/chunk-3RW4AZJV.js +5063 -0
- package/chunks/{chunk-NSSVORTQ.js → chunk-3UC7ZC43.js} +16 -12
- package/chunks/chunk-3VJ7MT3N.js +111 -0
- package/chunks/{chunk-DRS2HTNT.js → chunk-3X76L4UF.js} +5 -5
- package/chunks/{chunk-PPFWEV7G.js → chunk-4RQIB5UZ.js} +62 -62
- package/chunks/{chunk-EROWZQN7.js → chunk-57NRQM3P.js} +6 -6
- package/chunks/{chunk-L7OJ3ZO3.js → chunk-5ES5YPED.js} +1 -1
- package/chunks/{chunk-RNGAT2Y2.js → chunk-5WQF27GW.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-DM4E337C.js → chunk-6QVRLKTZ.js} +4 -4
- package/chunks/{chunk-RM3PGSGL.js → chunk-6SHO7WFF.js} +15 -2
- package/chunks/{chunk-LHMZCIKL.js → chunk-7Z6UEJA4.js} +3 -1
- package/chunks/{chunk-SBMHB6N5.js → chunk-A34EPIUV.js} +12 -12
- package/chunks/{chunk-6QTCOQX7.js → chunk-AGZF43UV.js} +1967 -1399
- package/chunks/{chunk-QHYITL6P.js → chunk-BOAWGUY6.js} +5 -11
- package/chunks/{chunk-TN6RT6EJ.js → chunk-C2QKQZEQ.js} +16 -4
- package/chunks/{chunk-BC4R5C5R.js → chunk-CEYA7K7C.js} +32 -6
- package/chunks/{chunk-R6RI2HIC.js → chunk-CLQPBI4H.js} +40 -13
- package/chunks/{chunk-OQHLUA2Y.js → chunk-DBF3HTLT.js} +3 -3
- package/chunks/{chunk-SJBIFVD2.js → chunk-DMSNJDWG.js} +5 -1
- package/chunks/{chunk-KKQWC6WS.js → chunk-DNV4FSN5.js} +1 -1
- package/chunks/chunk-DXXNMPJH.js +5468 -0
- package/chunks/{chunk-CBJE2PLG.js → chunk-FDY3XOTM.js} +2 -2
- package/chunks/{chunk-NDY7OENU.js → chunk-FPHA7WIZ.js} +2 -2
- package/chunks/{chunk-MNOXKSM2.js → chunk-FZ5NVRVK.js} +1 -1
- package/chunks/{chunk-UJT42DB6.js → chunk-GQBRGBLS.js} +5 -5
- package/chunks/{chunk-Y4UQT3PM.js → chunk-HCFSKO6K.js} +1 -1
- package/chunks/{chunk-2Z43HUXT.js → chunk-HLKG6CZN.js} +3 -2
- package/chunks/{chunk-WALEWZ44.js → chunk-IUSKVKH5.js} +1 -1
- package/chunks/{chunk-XKSCTXPK.js → chunk-J6ABRKAB.js} +2 -1
- package/chunks/{chunk-DX3TKXNT.js → chunk-JA5KWZTJ.js} +1 -1
- package/chunks/{chunk-CHY5C5T4.js → chunk-JN2VJ33O.js} +171 -79
- package/chunks/{chunk-YTFBURQD.js → chunk-KYTQOCDE.js} +1 -1
- package/chunks/{chunk-BPFJQGY7.js → chunk-LM3YCCZJ.js} +164 -5
- package/chunks/{chunk-ZISMVA6U.js → chunk-LXFCHX4X.js} +1371 -24
- package/chunks/{chunk-6KPZJJ6U.js → chunk-MBWLP5OT.js} +9 -9
- package/chunks/{chunk-IMAMNLY6.js → chunk-MHQKYQDS.js} +3 -3
- package/chunks/{chunk-M5ITDKSM.js → chunk-MJKEQSZI.js} +1 -1
- package/chunks/{chunk-MTNTVOJR.js → chunk-MJKMIQMK.js} +5 -2
- package/chunks/{chunk-CSPSJU5R.js → chunk-MX7CTJHR.js} +16 -16
- package/chunks/{chunk-HISPEX42.js → chunk-N2IJLN2L.js} +7 -7
- package/chunks/{chunk-YCU7QV7Q.js → chunk-N4YJQTRL.js} +4 -0
- package/chunks/{chunk-R3UWLLRQ.js → chunk-NUK2PFSU.js} +1 -1
- package/chunks/{chunk-YXK4GPYO.js → chunk-NVFJSIAX.js} +29 -0
- package/chunks/{chunk-4MCC4XHH.js → chunk-O2RJARYU.js} +38 -37
- package/chunks/{chunk-JKGCBO3O.js → chunk-OAYOHSGP.js} +3 -3
- package/chunks/{chunk-G4M7FPNY.js → chunk-OBVBTAX5.js} +1 -1
- package/chunks/{chunk-JJ6B3ZD3.js → chunk-OIFSBXSP.js} +2 -2
- package/chunks/{chunk-NNEJEBCF.js → chunk-QOKV6AO4.js} +30 -21
- package/chunks/{chunk-DG573EOO.js → chunk-RZORUN6X.js} +1 -1
- package/chunks/{chunk-RSBQS6M4.js → chunk-SL2P3JUA.js} +1 -1
- package/chunks/{chunk-K4I4STSL.js → chunk-SOT7OMGL.js} +2 -2
- package/chunks/{chunk-MDBNFHIO.js → chunk-SRNPMG7J.js} +3 -3
- package/chunks/{chunk-SJVPSHXU.js → chunk-UNXGEDX2.js} +4 -4
- package/chunks/{chunk-WZ724G6K.js → chunk-UTL7KABL.js} +5 -5
- package/chunks/{chunk-UY2TCIZS.js → chunk-V5VTULL5.js} +2 -2
- package/chunks/{chunk-Z7XNVNPM.js → chunk-V6NH3CUC.js} +1 -1
- package/chunks/{chunk-J3ERRYYI.js → chunk-WXUDZHOJ.js} +2 -2
- package/chunks/{chunk-2CAII5HD.js → chunk-XH7H6YG4.js} +1 -1
- package/chunks/{chunk-XKZXGIRM.js → chunk-YSU33ACT.js} +2 -2
- package/chunks/{chunk-6QVQZAW6.js → chunk-YTWX5TT2.js} +1 -1
- package/chunks/{chunk-5B2WNM6V.js → chunk-ZI4MGBB5.js} +1 -1
- package/chunks/{chunk-2YH27UNF.js → chunk-ZO5EA3XJ.js} +1 -1
- package/chunks/{computer-use-ON3JQUHW.js → computer-use-5S3NVXRA.js} +11 -11
- package/chunks/{contextCommand-OGCG7W6N.js → contextCommand-DPBALZFK.js} +13 -13
- package/chunks/{cron-create-6YTCOX6P.js → cron-create-7JYUDTUY.js} +20 -5
- package/chunks/{cron-delete-E3NIFSUK.js → cron-delete-YPULQQAK.js} +2 -2
- package/chunks/{cron-list-Q64MNQNE.js → cron-list-HJIW5MHP.js} +2 -2
- package/chunks/{daemon-EEB2RYOL.js → daemon-7XYW4BC3.js} +102 -0
- package/chunks/{daemon-status-provider-P72STMLB.js → daemon-status-provider-2EWTHT7Y.js} +20 -19
- 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-BV56HW3W.js} +276 -95
- package/chunks/{dist-IZP2VV4C.js → dist-JPSVN367.js} +2 -2
- package/chunks/{earlyInputCapture-DAFHSGVW.js → earlyInputCapture-GGPV4IFT.js} +11 -11
- package/chunks/{edit-3QFNCSZH.js → edit-HJ7ISN4C.js} +12 -12
- package/chunks/{en-M4EBUBNU.js → en-XR3S5VWY.js} +1 -0
- package/chunks/{enter-worktree-62EQQMLD.js → enter-worktree-2BQT675D.js} +11 -11
- package/chunks/{enterPlanMode-VUQSE4EG.js → enterPlanMode-SJXHJ3WD.js} +11 -11
- package/chunks/{errors-PW75PZXE.js → errors-EVGER4AZ.js} +13 -13
- package/chunks/{exit-worktree-VVNH7OVY.js → exit-worktree-RPDDOSPM.js} +11 -11
- package/chunks/{exitPlanMode-RUYRCYZW.js → exitPlanMode-BQEROAJ7.js} +11 -11
- package/chunks/{fast-path-TFRJRTTR.js → fast-path-FX2ICJ2O.js} +3 -3
- package/chunks/{fast-path-settings-UQLRFDQP.js → fast-path-settings-RCRXH2JG.js} +2 -2
- package/chunks/{gemini-XW7ZDUVR.js → gemini-EHUXCOUI.js} +69 -64
- package/chunks/{geminiContentGenerator-MZDVHVZH.js → geminiContentGenerator-YDUUKAM2.js} +1 -1
- package/chunks/{glob-WAY2PUWA.js → glob-3VIGV2DL.js} +11 -11
- package/chunks/{grep-W6CBKSYC.js → grep-4D3S4NUC.js} +11 -11
- package/chunks/{initializer-HK2XE6P2.js → initializer-QZTZSSLW.js} +16 -16
- package/chunks/{list-RVLIIKKL.js → list-WQ24EAMK.js} +18 -18
- package/chunks/{loadedSettingsAdapter-C63OUYZC.js → loadedSettingsAdapter-XV74KOSR.js} +16 -16
- package/chunks/{loop-wakeup-G2EHBRGR.js → loop-wakeup-34YK7T7O.js} +3 -3
- package/chunks/{ls-IDHUVSAG.js → ls-MPD5OJUX.js} +1 -1
- package/chunks/{lsp-FSRYXGFT.js → lsp-72PWTDW7.js} +1 -1
- package/chunks/{workspace-skills-status-ONEPXJV6.js → mcp-CO3MKM7N.js} +20 -16
- package/chunks/{monitor-FOG36ABM.js → monitor-GB56T65A.js} +11 -11
- package/chunks/{nonInteractiveCli-6BYQSJTB.js → nonInteractiveCli-HNZRIM5I.js} +46 -44
- package/chunks/{notebook-edit-GC6NXRCX.js → notebook-edit-VMXAAE3R.js} +12 -12
- package/chunks/{openaiContentGenerator-EXR3ZL3Z.js → openaiContentGenerator-GM77FLII.js} +6 -6
- package/chunks/{pidfile-FNZM2DDH.js → pidfile-HFXSHR64.js} +11 -11
- package/chunks/{qwenContentGenerator-A7B6J4U7.js → qwenContentGenerator-QSCXQIKJ.js} +13 -13
- package/chunks/{read-file-6JL4ULMY.js → read-file-SVH6CGQY.js} +3 -3
- package/chunks/{read-mcp-resource-PIJF24RO.js → read-mcp-resource-OWOBJY72.js} +1 -1
- package/chunks/record-artifact-URK3YUDJ.js +343 -0
- package/chunks/{ripGrep-DIUGLJE5.js → ripGrep-JD5O2FLX.js} +11 -11
- package/chunks/{run-qwen-serve-CME3AKM4.js → run-qwen-serve-FADLRJUN.js} +67 -28
- package/chunks/{scheduler-L7F6GDDT.js → scheduler-Q65SB7DJ.js} +11 -11
- package/chunks/{send-message-33PYFMCT.js → send-message-L7OLQEKH.js} +2 -2
- package/chunks/{serve-SRCBOJGP.js → serve-6ZXAMQ4M.js} +18 -18
- package/chunks/{server-QSQ45QFR.js → server-WKDQA6XR.js} +1184 -490
- package/chunks/{session-5DG6NXHZ.js → session-STWOX7RA.js} +48 -46
- package/chunks/{settings-3EEQI4MN.js → settings-LC4CCWQQ.js} +15 -15
- package/chunks/{shell-B7FNYF5S.js → shell-FEG3RLPW.js} +11 -11
- package/chunks/{skill-AAOGHD5O.js → skill-XTXAMDAP.js} +4 -4
- package/chunks/{spawnChannel-3CBN3ZLK.js → spawnChannel-B6JJPBPV.js} +15 -15
- package/chunks/{src-T5A7P7FS.js → src-HITDGVRM.js} +47 -21
- package/chunks/{startInteractiveUI-2FGEQ6AS.js → startInteractiveUI-IT423PW4.js} +354 -152
- package/chunks/{syntheticOutput-YOSWIHDJ.js → syntheticOutput-J3MLCQAR.js} +2 -2
- package/chunks/{task-create-NHS2NGB3.js → task-create-ELEBZ7H2.js} +3 -3
- package/chunks/{task-list-5UIB564R.js → task-list-IEUZLF3Y.js} +1 -1
- package/chunks/{task-stop-HGXZ2VZ3.js → task-stop-QEZW3UDY.js} +1 -1
- package/chunks/{task-update-IYYWUILG.js → task-update-DW36J5P5.js} +3 -3
- package/chunks/{team-create-KDF6W6PV.js → team-create-DAG6SNHZ.js} +11 -11
- package/chunks/{team-delete-FEKJCU4P.js → team-delete-SVITIMBO.js} +1 -1
- package/chunks/{team-plan-approval-PSFKQX7M.js → team-plan-approval-DRDY5OPC.js} +11 -11
- package/chunks/{theme-manager-5XOA2AO7.js → theme-manager-N67EZC6B.js} +11 -11
- package/chunks/{todoWrite-TKMVZ2HT.js → todoWrite-SFFQHZYY.js} +2 -2
- package/chunks/{tool-search-LFRILZXC.js → tool-search-CMDJ5HGM.js} +4 -4
- package/chunks/{trustedFolders-7HQY6T6X.js → trustedFolders-JD4QX6UJ.js} +12 -12
- package/chunks/{validateNonInterActiveAuth-UC27B7BA.js → validateNonInterActiveAuth-ADDCGZ6A.js} +43 -41
- package/chunks/version-VAONYVE5.js +10 -0
- package/chunks/{web-fetch-J4PIW36Q.js → web-fetch-SXAXJHIO.js} +2 -2
- package/chunks/{workflow-KUTESS6L.js → workflow-DG2BR42M.js} +20 -13
- package/chunks/{workspace-providers-status-LJT5AQDS.js → workspace-providers-status-XGW5OZTD.js} +18 -18
- package/chunks/{workspace-service-YOBYVDXH.js → workspace-service-GX3GGZLU.js} +23 -23
- package/chunks/workspace-skills-status-LFK5WV2V.js +68 -0
- package/chunks/{write-file-FJYBZUHP.js → write-file-UR7FXWOU.js} +12 -12
- package/chunks/yargs-B64EYTCF.js +10 -0
- package/chunks/{zh-SLZNSSZB.js → zh-FSVJTXA4.js} +1 -0
- package/chunks/{zh-TW-P53C2SL5.js → zh-TW-66MG4LWL.js} +1 -0
- package/cli-entry.js +81 -8
- package/cli.js +348 -55
- package/locales/en.js +1 -0
- package/locales/zh-TW.js +1 -0
- package/locales/zh.js +1 -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-CUpe0ibu.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-DUCzbHVo.js → architectureDiagram-3BPJPVTR-JvyrY_mK.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BEEBt1LL.js → blockDiagram-GPEHLZMM-CK3Y_vom.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-5ZJ_DeFL.js → c4Diagram-AAUBKEIU-DprSnyrf.js} +1 -1
- package/web-shell/assets/channel-BAxQ2-aZ.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-Cfw7EiLn.js → chunk-2J33WTMH-DJtRJPmu.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-FGuZNCZY.js → chunk-4BX2VUAB-ON6Q2-BG.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-CaBwYPBF.js → chunk-55IACEB6-c60ou5HZ.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-BlR04OFz.js → chunk-727SXJPM-BamtPKxx.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-D3_mYJH5.js → chunk-AQP2D5EJ-CsVgpu-T.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-7D4q4SbB.js → chunk-FMBD7UC4-vZrpjAx4.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-BjX_Iwmr.js → chunk-ND2GUHAM-qxyNOd5t.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-C3Hz_ZQh.js → chunk-QZHKN3VN-BvTJSM_S.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-Cvd_xhZI.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Cvd_xhZI.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-Ax4UycaT.js → cose-bilkent-S5V4N54A-1tXB4pju.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-C6hmPtGt.js → dagre-BM42HDAG-DglBzme8.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-tXZnxjmw.js → diagram-2AECGRRQ-DEJpqsWz.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-99dwIzQG.js → diagram-5GNKFQAL-CsQ1NrMG.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-Bqhn0-2s.js → diagram-KO2AKTUF-Z-3codAi.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DzThVSvo.js → diagram-LMA3HP47-mBuPTA2i.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-DPE8vjln.js → diagram-OG6HWLK6-tcA3K3s9.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-KzUKgQCV.js → erDiagram-TEJ5UH35-D9bXFRyZ.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-DBN-DXw5.js → flowDiagram-I6XJVG4X-Ck0Py04s.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-DuBsP9u8.js → ganttDiagram-6RSMTGT7-rOevCekE.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BjWHMyKR.js → gitGraphDiagram-PVQCEYII-CoPQaLj0.js} +1 -1
- package/web-shell/assets/index-Cr7MYW6T.css +5 -0
- package/web-shell/assets/index-DCHPAUp3.js +730 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-BVux0vP6.js → infoDiagram-5YYISTIA-a77CUKoI.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-2qzw7f--.js → ishikawaDiagram-YF4QCWOH-DlLgUAO-.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-Dnl65sxL.js → journeyDiagram-JHISSGLW-BXR5kVAZ.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-BElSQYtY.js → kanban-definition-UN3LZRKU-h5CoHZg7.js} +1 -1
- package/web-shell/assets/{linear-BjoycSSY.js → linear-BkaREbyD.js} +1 -1
- package/web-shell/assets/{mermaid.core-xe6bvMRz.js → mermaid.core-Bkagz0ng.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-D8DQgI4U.js → mindmap-definition-RKZ34NQL-D7EMKR_5.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-Dwh7Gp7c.js → pieDiagram-4H26LBE5-DAmPOjsL.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BXKNBln2.js → quadrantDiagram-W4KKPZXB-e4WFQkQu.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BzaC3cIA.js → requirementDiagram-4Y6WPE33-v1zo7OiV.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-DP2t7eZk.js → sankeyDiagram-5OEKKPKP-Bstm4aW_.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-XlFiWEYv.js → sequenceDiagram-3UESZ5HK-DzcZy6xN.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CupgUMJO.js → stateDiagram-AJRCARHV-BEJH6YbH.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BopifCBI.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-DstuGywa.js → timeline-definition-PNZ67QCA-TI1wH-Pm.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-CnbNp6zu.js → vennDiagram-CIIHVFJN-YaH8VDMS.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-DnvoHq6R.js → wardley-L42UT6IY-B80co7OP.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-Cz0xHEWB.js → wardleyDiagram-YWT4CUSO-4fHNDEMl.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-p36gfo88.js → xychartDiagram-2RQKCTM6-DT3q4Z3J.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/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
|
@@ -34,9 +34,14 @@ import {
|
|
|
34
34
|
EVENT_SCHEMA_VERSION,
|
|
35
35
|
EventBus
|
|
36
36
|
} from "./chunk-ALX6BUYW.js";
|
|
37
|
+
import {
|
|
38
|
+
ClientSideConnection,
|
|
39
|
+
PROTOCOL_VERSION,
|
|
40
|
+
RequestError
|
|
41
|
+
} from "./chunk-VRDMOSQS.js";
|
|
37
42
|
import {
|
|
38
43
|
defaultSpawnChannelFactory
|
|
39
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-57NRQM3P.js";
|
|
40
45
|
import {
|
|
41
46
|
BridgeChannelClosedError,
|
|
42
47
|
BridgeTimeoutError,
|
|
@@ -45,20 +50,15 @@ import {
|
|
|
45
50
|
STATUS_SCHEMA_VERSION,
|
|
46
51
|
createIdleWorkspaceExtensionsStatus,
|
|
47
52
|
createIdleWorkspaceHooksStatus
|
|
48
|
-
} from "./chunk-
|
|
49
|
-
import {
|
|
50
|
-
ClientSideConnection,
|
|
51
|
-
PROTOCOL_VERSION,
|
|
52
|
-
RequestError
|
|
53
|
-
} from "./chunk-UFC57OYT.js";
|
|
53
|
+
} from "./chunk-7Z6UEJA4.js";
|
|
54
54
|
import {
|
|
55
55
|
ShellExecutionService,
|
|
56
56
|
TrustGateError
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-AGZF43UV.js";
|
|
58
58
|
import {
|
|
59
59
|
DAEMON_TRACEPARENT_META_KEY,
|
|
60
60
|
DAEMON_TRACESTATE_META_KEY
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-JN2VJ33O.js";
|
|
62
62
|
import {
|
|
63
63
|
init_esbuild_shims
|
|
64
64
|
} from "./chunk-A4BMJM77.js";
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
// packages/acp-bridge/src/bridge.ts
|
|
70
70
|
init_esbuild_shims();
|
|
71
71
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
72
|
-
import * as
|
|
72
|
+
import * as path3 from "node:path";
|
|
73
73
|
|
|
74
74
|
// packages/acp-bridge/src/compactionEngine.ts
|
|
75
75
|
init_esbuild_shims();
|
|
@@ -943,8 +943,8 @@ var MultiClientPermissionMediator = class {
|
|
|
943
943
|
}
|
|
944
944
|
this.resolved.set(record.requestId, record);
|
|
945
945
|
while (this.resolvedOrder.length > MAX_RESOLVED_PERMISSION_RECORDS) {
|
|
946
|
-
const
|
|
947
|
-
if (
|
|
946
|
+
const oldest2 = this.resolvedOrder.shift();
|
|
947
|
+
if (oldest2 !== void 0) this.resolved.delete(oldest2);
|
|
948
948
|
}
|
|
949
949
|
}
|
|
950
950
|
safeEmit(sessionId, event) {
|
|
@@ -1035,10 +1035,108 @@ var MultiClientPermissionMediator = class {
|
|
|
1035
1035
|
};
|
|
1036
1036
|
|
|
1037
1037
|
// packages/acp-bridge/src/bridgeClient.ts
|
|
1038
|
+
var PUBLISH_ARTIFACT_TOOL_NAME = "artifact";
|
|
1038
1039
|
function isFsErrorShape(err) {
|
|
1039
1040
|
return err instanceof Error && err.name === "FsError" && typeof err.kind === "string";
|
|
1040
1041
|
}
|
|
1041
1042
|
__name(isFsErrorShape, "isFsErrorShape");
|
|
1043
|
+
function isRecord(value) {
|
|
1044
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1045
|
+
}
|
|
1046
|
+
__name(isRecord, "isRecord");
|
|
1047
|
+
function artifactPayloadFields(artifact) {
|
|
1048
|
+
return {
|
|
1049
|
+
title: artifact["title"],
|
|
1050
|
+
kind: artifact["kind"],
|
|
1051
|
+
storage: artifact["storage"],
|
|
1052
|
+
description: artifact["description"],
|
|
1053
|
+
workspacePath: artifact["workspacePath"],
|
|
1054
|
+
managedId: artifact["managedId"],
|
|
1055
|
+
url: artifact["url"],
|
|
1056
|
+
mimeType: artifact["mimeType"],
|
|
1057
|
+
sizeBytes: artifact["sizeBytes"],
|
|
1058
|
+
metadata: artifact["metadata"]
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
__name(artifactPayloadFields, "artifactPayloadFields");
|
|
1062
|
+
function extractCappedArtifactInputs(rawArtifacts, limit, sessionId, source, toInput) {
|
|
1063
|
+
const artifacts = [];
|
|
1064
|
+
for (let index = 0; index < rawArtifacts.length; index++) {
|
|
1065
|
+
const artifact = rawArtifacts[index];
|
|
1066
|
+
if (!isRecord(artifact)) {
|
|
1067
|
+
writeStderrLine(
|
|
1068
|
+
`[artifacts] session=${sessionId} action=dropped reason=malformed source=${source} index=${index}`
|
|
1069
|
+
);
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
if (artifacts.length >= limit) {
|
|
1073
|
+
writeStderrLine(
|
|
1074
|
+
`[artifacts] session=${sessionId} action=dropped reason="artifact batch limit exceeded" source=${source} dropped=${rawArtifacts.length - index}`
|
|
1075
|
+
);
|
|
1076
|
+
break;
|
|
1077
|
+
}
|
|
1078
|
+
artifacts.push(toInput(artifact));
|
|
1079
|
+
}
|
|
1080
|
+
return artifacts;
|
|
1081
|
+
}
|
|
1082
|
+
__name(extractCappedArtifactInputs, "extractCappedArtifactInputs");
|
|
1083
|
+
function artifactIngestionErrorReason(error) {
|
|
1084
|
+
if (!(error instanceof Error)) {
|
|
1085
|
+
return String(error);
|
|
1086
|
+
}
|
|
1087
|
+
return {
|
|
1088
|
+
name: error.name,
|
|
1089
|
+
message: error.message,
|
|
1090
|
+
stack: error.stack?.split("\n").slice(0, 4).join("\n")
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
__name(artifactIngestionErrorReason, "artifactIngestionErrorReason");
|
|
1094
|
+
function extractSessionUpdateArtifacts(params, updateMeta, limit, sessionId) {
|
|
1095
|
+
const rawArtifacts = updateMeta?.["artifacts"];
|
|
1096
|
+
if (!Array.isArray(rawArtifacts)) {
|
|
1097
|
+
return [];
|
|
1098
|
+
}
|
|
1099
|
+
const update = params.update;
|
|
1100
|
+
if (update.sessionUpdate !== "tool_call_update" || update.status !== "completed" && update.status !== "failed" && update.status !== "cancelled") {
|
|
1101
|
+
return [];
|
|
1102
|
+
}
|
|
1103
|
+
const toolCallId = typeof update.toolCallId === "string" ? update.toolCallId : void 0;
|
|
1104
|
+
const toolName = typeof updateMeta?.["toolName"] === "string" ? updateMeta["toolName"] : void 0;
|
|
1105
|
+
return extractCappedArtifactInputs(
|
|
1106
|
+
rawArtifacts,
|
|
1107
|
+
limit,
|
|
1108
|
+
sessionId,
|
|
1109
|
+
"tool",
|
|
1110
|
+
(artifact) => ({
|
|
1111
|
+
...artifactPayloadFields(artifact),
|
|
1112
|
+
source: "tool",
|
|
1113
|
+
toolCallId,
|
|
1114
|
+
toolName
|
|
1115
|
+
})
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
__name(extractSessionUpdateArtifacts, "extractSessionUpdateArtifacts");
|
|
1119
|
+
function sanitizeSessionUpdateArtifacts(params, updateMeta) {
|
|
1120
|
+
if (!Array.isArray(updateMeta?.["artifacts"])) {
|
|
1121
|
+
return params;
|
|
1122
|
+
}
|
|
1123
|
+
const sanitizedMeta = { ...updateMeta };
|
|
1124
|
+
delete sanitizedMeta["artifacts"];
|
|
1125
|
+
const update = {
|
|
1126
|
+
...params.update,
|
|
1127
|
+
_meta: sanitizedMeta
|
|
1128
|
+
};
|
|
1129
|
+
return {
|
|
1130
|
+
...params,
|
|
1131
|
+
update
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
__name(sanitizeSessionUpdateArtifacts, "sanitizeSessionUpdateArtifacts");
|
|
1135
|
+
function isTrustedArtifactToolUpdate(params, updateMeta) {
|
|
1136
|
+
const update = params.update;
|
|
1137
|
+
return update.sessionUpdate === "tool_call_update" && update.status === "completed" && updateMeta?.["toolName"] === PUBLISH_ARTIFACT_TOOL_NAME;
|
|
1138
|
+
}
|
|
1139
|
+
__name(isTrustedArtifactToolUpdate, "isTrustedArtifactToolUpdate");
|
|
1042
1140
|
function preserveFsErrorOverAcp(err) {
|
|
1043
1141
|
if (isFsErrorShape(err)) {
|
|
1044
1142
|
throw new RequestError(-32603, err.message, {
|
|
@@ -1100,7 +1198,7 @@ function sliceLineRange(content, startLine, endLine) {
|
|
|
1100
1198
|
}
|
|
1101
1199
|
__name(sliceLineRange, "sliceLineRange");
|
|
1102
1200
|
var BridgeClient = class {
|
|
1103
|
-
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender) {
|
|
1201
|
+
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender, ownsSession = () => true) {
|
|
1104
1202
|
this.resolveEntry = resolveEntry;
|
|
1105
1203
|
this.resolvePendingRestoreEvents = resolvePendingRestoreEvents;
|
|
1106
1204
|
this.mediator = mediator;
|
|
@@ -1110,6 +1208,7 @@ var BridgeClient = class {
|
|
|
1110
1208
|
this.onModelPromoted = onModelPromoted;
|
|
1111
1209
|
this.onModePromoted = onModePromoted;
|
|
1112
1210
|
this.clientMcpSender = clientMcpSender;
|
|
1211
|
+
this.ownsSession = ownsSession;
|
|
1113
1212
|
}
|
|
1114
1213
|
static {
|
|
1115
1214
|
__name(this, "BridgeClient");
|
|
@@ -1163,6 +1262,12 @@ var BridgeClient = class {
|
|
|
1163
1262
|
}
|
|
1164
1263
|
}
|
|
1165
1264
|
async sessionUpdate(params) {
|
|
1265
|
+
if (!this.ownsSession(params.sessionId) && !this.inFlightRestoreIds.has(params.sessionId)) {
|
|
1266
|
+
writeStderrLine(
|
|
1267
|
+
`[demux] session=${params.sessionId} type=session_update action=dropped reason=session_not_owned`
|
|
1268
|
+
);
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1166
1271
|
const entry = this.resolveEntry(params.sessionId);
|
|
1167
1272
|
const events = entry?.events ?? this.resolvePendingRestoreEvents(params.sessionId);
|
|
1168
1273
|
if (!events) return;
|
|
@@ -1192,12 +1297,26 @@ var BridgeClient = class {
|
|
|
1192
1297
|
const updateMeta = params.update._meta;
|
|
1193
1298
|
const originalTs = updateMeta?.["serverTimestamp"] ?? updateMeta?.["timestamp"];
|
|
1194
1299
|
const serverTimestamp = typeof originalTs === "number" && Number.isFinite(originalTs) ? originalTs : void 0;
|
|
1300
|
+
const artifacts = entry?.artifacts ? extractSessionUpdateArtifacts(
|
|
1301
|
+
params,
|
|
1302
|
+
updateMeta,
|
|
1303
|
+
entry.artifacts.inputBatchLimit(),
|
|
1304
|
+
entry.sessionId
|
|
1305
|
+
) : [];
|
|
1306
|
+
const publishParams = sanitizeSessionUpdateArtifacts(params, updateMeta);
|
|
1195
1307
|
events.publish({
|
|
1196
1308
|
type: "session_update",
|
|
1197
|
-
data:
|
|
1309
|
+
data: publishParams,
|
|
1198
1310
|
...originator,
|
|
1199
1311
|
...serverTimestamp !== void 0 ? { _meta: { serverTimestamp } } : {}
|
|
1200
1312
|
});
|
|
1313
|
+
if (entry) {
|
|
1314
|
+
if (artifacts.length > 0) {
|
|
1315
|
+
await this.upsertAndPublishArtifacts(entry, artifacts, {
|
|
1316
|
+
trustedPublisher: isTrustedArtifactToolUpdate(params, updateMeta)
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1201
1320
|
}
|
|
1202
1321
|
/**
|
|
1203
1322
|
* Bounded early-event buffer. Frames are keyed by sessionId; each
|
|
@@ -1335,11 +1454,12 @@ var BridgeClient = class {
|
|
|
1335
1454
|
return { payload: response };
|
|
1336
1455
|
}
|
|
1337
1456
|
/**
|
|
1338
|
-
* Handle child->bridge ACP `extNotification` calls.
|
|
1339
|
-
*
|
|
1457
|
+
* Handle child->bridge ACP `extNotification` calls. Recognized methods are
|
|
1458
|
+
* `qwen/notify/session/model-update`,
|
|
1340
1459
|
* `qwen/notify/session/mode-update`,
|
|
1341
1460
|
* `qwen/notify/session/title-update` (auto/in-process session titles),
|
|
1342
1461
|
* `qwen/notify/session/prompt-suggestion` (followup assist),
|
|
1462
|
+
* `qwen/notify/session/artifact-event` (hook artifacts),
|
|
1343
1463
|
* `qwen/notify/session/terminal-sequence`, and
|
|
1344
1464
|
* `qwen/notify/session/mcp-budget-event` — each translated into a
|
|
1345
1465
|
* session-scoped SSE frame. Unknown methods are dropped silently
|
|
@@ -1401,6 +1521,10 @@ var BridgeClient = class {
|
|
|
1401
1521
|
this.publishExtNotification(sessionId2, "terminal_sequence", rest2);
|
|
1402
1522
|
return;
|
|
1403
1523
|
}
|
|
1524
|
+
if (method === "qwen/notify/session/artifact-event") {
|
|
1525
|
+
await this.handleArtifactEvent(params);
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1404
1528
|
if (method !== "qwen/notify/session/mcp-budget-event") return;
|
|
1405
1529
|
const sessionId = params["sessionId"];
|
|
1406
1530
|
if (typeof sessionId !== "string") return;
|
|
@@ -1419,6 +1543,67 @@ var BridgeClient = class {
|
|
|
1419
1543
|
void _kind;
|
|
1420
1544
|
this.publishExtNotification(sessionId, type, rest);
|
|
1421
1545
|
}
|
|
1546
|
+
async handleArtifactEvent(params) {
|
|
1547
|
+
const sessionId = params["sessionId"];
|
|
1548
|
+
const rawArtifacts = params["artifacts"];
|
|
1549
|
+
if (typeof sessionId !== "string" || !Array.isArray(rawArtifacts)) {
|
|
1550
|
+
writeStderrLine(
|
|
1551
|
+
`[demux] session=${typeof sessionId === "string" ? sessionId : "<missing>"} type=artifact_event action=dropped reason=malformed`
|
|
1552
|
+
);
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
if (!this.ownsSession(sessionId) && !this.inFlightRestoreIds.has(sessionId)) {
|
|
1556
|
+
writeStderrLine(
|
|
1557
|
+
`[demux] session=${sessionId} type=artifact_event action=dropped reason=session_not_owned`
|
|
1558
|
+
);
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
const entry = this.resolveEntry(sessionId);
|
|
1562
|
+
if (!entry) {
|
|
1563
|
+
writeStderrLine(
|
|
1564
|
+
`[demux] session=${sessionId} type=artifact_event action=dropped reason=session_not_found`
|
|
1565
|
+
);
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
const hookEventName = typeof params["hookEventName"] === "string" ? params["hookEventName"] : void 0;
|
|
1569
|
+
const toolName = typeof params["toolName"] === "string" ? params["toolName"] : void 0;
|
|
1570
|
+
const toolCallId = typeof params["toolCallId"] === "string" ? params["toolCallId"] : void 0;
|
|
1571
|
+
const artifacts = extractCappedArtifactInputs(
|
|
1572
|
+
rawArtifacts,
|
|
1573
|
+
entry.artifacts.inputBatchLimit(),
|
|
1574
|
+
entry.sessionId,
|
|
1575
|
+
"hook",
|
|
1576
|
+
(artifact) => ({
|
|
1577
|
+
...artifactPayloadFields(artifact),
|
|
1578
|
+
source: "hook",
|
|
1579
|
+
hookEventName,
|
|
1580
|
+
toolName,
|
|
1581
|
+
toolCallId
|
|
1582
|
+
})
|
|
1583
|
+
);
|
|
1584
|
+
await this.upsertAndPublishArtifacts(entry, artifacts);
|
|
1585
|
+
}
|
|
1586
|
+
async upsertAndPublishArtifacts(entry, artifacts, options) {
|
|
1587
|
+
try {
|
|
1588
|
+
const result = await entry.artifacts.upsertMany(artifacts, options);
|
|
1589
|
+
this.publishArtifactChanges(entry, result.changes);
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
writeStderrLine(
|
|
1592
|
+
`[artifacts] session=${entry.sessionId} action=dropped reason=${JSON.stringify(
|
|
1593
|
+
artifactIngestionErrorReason(error)
|
|
1594
|
+
)}`
|
|
1595
|
+
);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
publishArtifactChanges(entry, changes) {
|
|
1599
|
+
for (const change of changes) {
|
|
1600
|
+
entry.events.publish({
|
|
1601
|
+
type: "artifact_changed",
|
|
1602
|
+
data: { sessionId: entry.sessionId, change },
|
|
1603
|
+
...entry.activePromptOriginatorClientId ? { originatorClientId: entry.activePromptOriginatorClientId } : {}
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1422
1607
|
publishExtNotification(sessionId, type, data) {
|
|
1423
1608
|
const entry = this.resolveEntry(sessionId);
|
|
1424
1609
|
const frame = {
|
|
@@ -1858,6 +2043,1005 @@ function extractA2uiToolUpdate(params) {
|
|
|
1858
2043
|
}
|
|
1859
2044
|
__name(extractA2uiToolUpdate, "extractA2uiToolUpdate");
|
|
1860
2045
|
|
|
2046
|
+
// packages/acp-bridge/src/sessionArtifacts.ts
|
|
2047
|
+
init_esbuild_shims();
|
|
2048
|
+
import { createHash } from "node:crypto";
|
|
2049
|
+
import { promises as fs2 } from "node:fs";
|
|
2050
|
+
import path2 from "node:path";
|
|
2051
|
+
var SOURCE_RESERVATIONS = {
|
|
2052
|
+
tool: 100,
|
|
2053
|
+
client: 50,
|
|
2054
|
+
hook: 50
|
|
2055
|
+
};
|
|
2056
|
+
var WORKSPACE_STATUS_REFRESH_TTL_MS = 5e3;
|
|
2057
|
+
var WORKSPACE_STATUS_REFRESH_BATCH_SIZE = 20;
|
|
2058
|
+
var SessionArtifactValidationError = class extends Error {
|
|
2059
|
+
constructor(message, field) {
|
|
2060
|
+
super(message);
|
|
2061
|
+
this.field = field;
|
|
2062
|
+
this.name = "SessionArtifactValidationError";
|
|
2063
|
+
}
|
|
2064
|
+
static {
|
|
2065
|
+
__name(this, "SessionArtifactValidationError");
|
|
2066
|
+
}
|
|
2067
|
+
code = "VALIDATION_FAILED";
|
|
2068
|
+
};
|
|
2069
|
+
var SessionArtifactStore = class {
|
|
2070
|
+
static {
|
|
2071
|
+
__name(this, "SessionArtifactStore");
|
|
2072
|
+
}
|
|
2073
|
+
sessionId;
|
|
2074
|
+
workspaceCwd;
|
|
2075
|
+
maxArtifacts;
|
|
2076
|
+
artifacts = /* @__PURE__ */ new Map();
|
|
2077
|
+
receivedSeq = 0;
|
|
2078
|
+
insertSeq = 0;
|
|
2079
|
+
realWorkspaceCwdPromise;
|
|
2080
|
+
operationQueue = Promise.resolve();
|
|
2081
|
+
constructor(options) {
|
|
2082
|
+
this.sessionId = options.sessionId;
|
|
2083
|
+
this.workspaceCwd = options.workspaceCwd;
|
|
2084
|
+
this.maxArtifacts = options.maxArtifacts ?? 200;
|
|
2085
|
+
}
|
|
2086
|
+
inputBatchLimit() {
|
|
2087
|
+
return this.maxArtifacts * 2;
|
|
2088
|
+
}
|
|
2089
|
+
async list() {
|
|
2090
|
+
return this.enqueue(async () => {
|
|
2091
|
+
await this.refreshWorkspaceStatuses();
|
|
2092
|
+
return {
|
|
2093
|
+
v: 1,
|
|
2094
|
+
sessionId: this.sessionId,
|
|
2095
|
+
artifacts: Array.from(this.artifacts.values()).sort((a, b) => a.insertSeq - b.insertSeq).map(toPublicArtifact),
|
|
2096
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2097
|
+
limits: { maxArtifacts: this.maxArtifacts }
|
|
2098
|
+
};
|
|
2099
|
+
});
|
|
2100
|
+
}
|
|
2101
|
+
async upsertMany(inputs, options = {}) {
|
|
2102
|
+
return this.enqueue(async () => {
|
|
2103
|
+
const normalizedResults = [];
|
|
2104
|
+
for (const input of inputs) {
|
|
2105
|
+
try {
|
|
2106
|
+
normalizedResults.push(
|
|
2107
|
+
await this.normalizeInput(
|
|
2108
|
+
input,
|
|
2109
|
+
++this.receivedSeq,
|
|
2110
|
+
options.trustedPublisher === true
|
|
2111
|
+
)
|
|
2112
|
+
);
|
|
2113
|
+
} catch (error) {
|
|
2114
|
+
if (options.strict) {
|
|
2115
|
+
throw error;
|
|
2116
|
+
}
|
|
2117
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2118
|
+
writeStderrLine(
|
|
2119
|
+
`[artifacts] session=${this.sessionId} action=dropped reason=${JSON.stringify(
|
|
2120
|
+
message
|
|
2121
|
+
)}`
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
const changes = [];
|
|
2126
|
+
for (const artifact of coalesceByIdentity(normalizedResults)) {
|
|
2127
|
+
const existing = this.artifacts.get(artifact.id) ?? this.findPublishedUpgradeTarget(artifact) ?? this.findPublishedWorkspaceTarget(artifact);
|
|
2128
|
+
if (!existing) {
|
|
2129
|
+
const stored = {
|
|
2130
|
+
...artifact,
|
|
2131
|
+
insertSeq: ++this.insertSeq
|
|
2132
|
+
};
|
|
2133
|
+
this.artifacts.set(stored.id, stored);
|
|
2134
|
+
changes.push({
|
|
2135
|
+
action: "created",
|
|
2136
|
+
artifactId: stored.id,
|
|
2137
|
+
artifact: toPublicArtifact(stored)
|
|
2138
|
+
});
|
|
2139
|
+
continue;
|
|
2140
|
+
}
|
|
2141
|
+
const updated = mergeArtifact(existing, artifact);
|
|
2142
|
+
if (updated.changed) {
|
|
2143
|
+
if (updated.artifact.id !== existing.id) {
|
|
2144
|
+
this.artifacts.delete(existing.id);
|
|
2145
|
+
}
|
|
2146
|
+
this.artifacts.set(updated.artifact.id, updated.artifact);
|
|
2147
|
+
changes.push({
|
|
2148
|
+
action: "updated",
|
|
2149
|
+
artifactId: updated.artifact.id,
|
|
2150
|
+
artifact: toPublicArtifact(updated.artifact)
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
const createdIds = new Set(
|
|
2155
|
+
changes.filter((change) => change.action === "created").map((change) => change.artifactId)
|
|
2156
|
+
);
|
|
2157
|
+
changes.push(...await this.evictOverflow(createdIds, changes));
|
|
2158
|
+
return { v: 1, sessionId: this.sessionId, changes };
|
|
2159
|
+
});
|
|
2160
|
+
}
|
|
2161
|
+
findPublishedUpgradeTarget(artifact) {
|
|
2162
|
+
if (artifact.storage !== "published" || !artifact.trustedPublisher || !artifact.managedId || !artifact.url) {
|
|
2163
|
+
return void 0;
|
|
2164
|
+
}
|
|
2165
|
+
const byUrl = this.artifacts.get(
|
|
2166
|
+
stableArtifactId(this.sessionId, `url:${artifact.url}`)
|
|
2167
|
+
);
|
|
2168
|
+
if (byUrl && (byUrl.storage !== "published" || byUrl.managedId === artifact.managedId)) {
|
|
2169
|
+
return byUrl;
|
|
2170
|
+
}
|
|
2171
|
+
for (const existing of this.artifacts.values()) {
|
|
2172
|
+
if (existing.storage === "workspace" && existing.workspacePath && artifact.managedId === managedIdForWorkspacePath(
|
|
2173
|
+
this.workspaceCwd,
|
|
2174
|
+
existing.workspacePath
|
|
2175
|
+
) || existing.storage === "published" && existing.managedId === artifact.managedId) {
|
|
2176
|
+
return existing;
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
return void 0;
|
|
2180
|
+
}
|
|
2181
|
+
findPublishedWorkspaceTarget(artifact) {
|
|
2182
|
+
if (artifact.storage !== "workspace" || !artifact.workspacePath) {
|
|
2183
|
+
return void 0;
|
|
2184
|
+
}
|
|
2185
|
+
const managedId = managedIdForWorkspacePath(
|
|
2186
|
+
this.workspaceCwd,
|
|
2187
|
+
artifact.workspacePath
|
|
2188
|
+
);
|
|
2189
|
+
for (const existing of this.artifacts.values()) {
|
|
2190
|
+
if (existing.storage === "published" && existing.managedId === managedId) {
|
|
2191
|
+
return existing;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return void 0;
|
|
2195
|
+
}
|
|
2196
|
+
async remove(artifactId, options) {
|
|
2197
|
+
return this.enqueue(async () => {
|
|
2198
|
+
const existing = this.artifacts.get(artifactId);
|
|
2199
|
+
if (!existing) {
|
|
2200
|
+
return { v: 1, sessionId: this.sessionId, changes: [] };
|
|
2201
|
+
}
|
|
2202
|
+
if (existing.source === "client" && existing.clientId !== void 0 && existing.clientId !== options?.clientId) {
|
|
2203
|
+
writeStderrLine(
|
|
2204
|
+
`[artifacts] session=${this.sessionId} action=remove_denied artifactId=${artifactId} owner=${existing.clientId} requester=${options?.clientId ?? "<anonymous>"}`
|
|
2205
|
+
);
|
|
2206
|
+
return { v: 1, sessionId: this.sessionId, changes: [] };
|
|
2207
|
+
}
|
|
2208
|
+
this.artifacts.delete(artifactId);
|
|
2209
|
+
return {
|
|
2210
|
+
v: 1,
|
|
2211
|
+
sessionId: this.sessionId,
|
|
2212
|
+
changes: [
|
|
2213
|
+
{
|
|
2214
|
+
action: "removed",
|
|
2215
|
+
artifactId,
|
|
2216
|
+
artifact: toPublicArtifact(existing),
|
|
2217
|
+
reason: "explicit"
|
|
2218
|
+
}
|
|
2219
|
+
]
|
|
2220
|
+
};
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2223
|
+
enqueue(operation) {
|
|
2224
|
+
const result = this.operationQueue.then(operation, operation);
|
|
2225
|
+
this.operationQueue = result.then(
|
|
2226
|
+
() => void 0,
|
|
2227
|
+
() => void 0
|
|
2228
|
+
);
|
|
2229
|
+
return result;
|
|
2230
|
+
}
|
|
2231
|
+
async normalizeInput(input, receivedSeq, trustedPublisherFromCaller) {
|
|
2232
|
+
if (!input || typeof input !== "object") {
|
|
2233
|
+
throw new SessionArtifactValidationError("Artifact must be an object");
|
|
2234
|
+
}
|
|
2235
|
+
const title = normalizeString(input.title, "title", 200, true);
|
|
2236
|
+
const description = normalizeString(
|
|
2237
|
+
input.description,
|
|
2238
|
+
"description",
|
|
2239
|
+
1e3,
|
|
2240
|
+
false
|
|
2241
|
+
);
|
|
2242
|
+
const source = input.source ?? "tool";
|
|
2243
|
+
if (source !== "tool" && source !== "hook" && source !== "client") {
|
|
2244
|
+
throw new SessionArtifactValidationError(
|
|
2245
|
+
"source must be tool, hook, or client",
|
|
2246
|
+
"source"
|
|
2247
|
+
);
|
|
2248
|
+
}
|
|
2249
|
+
const trustedPublisher = trustedPublisherFromCaller;
|
|
2250
|
+
const workspacePath = input.workspacePath ? normalizeWorkspacePath(input.workspacePath, this.workspaceCwd) : void 0;
|
|
2251
|
+
const managedId = normalizeManagedId(input.managedId);
|
|
2252
|
+
const rawStorage = input.storage;
|
|
2253
|
+
const storage = inferStorage(rawStorage, {
|
|
2254
|
+
workspacePath,
|
|
2255
|
+
managedId,
|
|
2256
|
+
url: input.url,
|
|
2257
|
+
trustedPublisher
|
|
2258
|
+
});
|
|
2259
|
+
const url = input.url ? normalizeArtifactUrl(input.url, trustedPublisher) : void 0;
|
|
2260
|
+
validateLocator(storage, {
|
|
2261
|
+
workspacePath,
|
|
2262
|
+
managedId,
|
|
2263
|
+
url,
|
|
2264
|
+
trustedPublisher
|
|
2265
|
+
});
|
|
2266
|
+
const metadata = normalizeMetadata(input.metadata);
|
|
2267
|
+
const workspaceStatus = workspacePath ? await this.getInitialWorkspaceStatus(workspacePath) : void 0;
|
|
2268
|
+
if (workspaceStatus?.escaped) {
|
|
2269
|
+
throw new SessionArtifactValidationError(
|
|
2270
|
+
"workspacePath must stay inside the workspace",
|
|
2271
|
+
"workspacePath"
|
|
2272
|
+
);
|
|
2273
|
+
}
|
|
2274
|
+
const kind = normalizeKind(
|
|
2275
|
+
input.kind ?? inferKind({ storage, workspacePath, url })
|
|
2276
|
+
);
|
|
2277
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2278
|
+
const identityKey = buildIdentityKey({
|
|
2279
|
+
storage,
|
|
2280
|
+
workspacePath,
|
|
2281
|
+
managedId,
|
|
2282
|
+
url
|
|
2283
|
+
});
|
|
2284
|
+
const id = stableArtifactId(this.sessionId, identityKey);
|
|
2285
|
+
return {
|
|
2286
|
+
id,
|
|
2287
|
+
identityKey,
|
|
2288
|
+
receivedSeq,
|
|
2289
|
+
retentionSource: source,
|
|
2290
|
+
trustedPublisher,
|
|
2291
|
+
kind,
|
|
2292
|
+
storage,
|
|
2293
|
+
source,
|
|
2294
|
+
status: workspaceStatus?.status ?? "available",
|
|
2295
|
+
...workspacePath ? { lastStatAt: Date.now() } : {},
|
|
2296
|
+
title,
|
|
2297
|
+
description,
|
|
2298
|
+
workspacePath,
|
|
2299
|
+
managedId,
|
|
2300
|
+
url,
|
|
2301
|
+
mimeType: normalizeString(input.mimeType, "mimeType", 120, false),
|
|
2302
|
+
sizeBytes: input.sizeBytes !== void 0 ? normalizeSizeBytes(input.sizeBytes) : workspaceStatus?.sizeBytes,
|
|
2303
|
+
metadata,
|
|
2304
|
+
clientRetained: source === "client",
|
|
2305
|
+
createdAt: now,
|
|
2306
|
+
updatedAt: now,
|
|
2307
|
+
toolCallId: normalizeString(input.toolCallId, "toolCallId", 200, false),
|
|
2308
|
+
toolName: normalizeString(input.toolName, "toolName", 200, false),
|
|
2309
|
+
hookEventName: normalizeString(
|
|
2310
|
+
input.hookEventName,
|
|
2311
|
+
"hookEventName",
|
|
2312
|
+
200,
|
|
2313
|
+
false
|
|
2314
|
+
),
|
|
2315
|
+
clientId: normalizeString(input.clientId, "clientId", 200, false)
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
async refreshWorkspaceStatuses() {
|
|
2319
|
+
const now = Date.now();
|
|
2320
|
+
const staleWorkspaceArtifacts = Array.from(this.artifacts.values()).filter((artifact) => artifact.workspacePath).filter((artifact) => shouldRefreshWorkspaceStatus(artifact, now));
|
|
2321
|
+
await runInBatches(
|
|
2322
|
+
staleWorkspaceArtifacts,
|
|
2323
|
+
WORKSPACE_STATUS_REFRESH_BATCH_SIZE,
|
|
2324
|
+
(artifact) => this.refreshWorkspaceStatus(artifact, {
|
|
2325
|
+
onError: "missing",
|
|
2326
|
+
now
|
|
2327
|
+
})
|
|
2328
|
+
);
|
|
2329
|
+
}
|
|
2330
|
+
async getInitialWorkspaceStatus(workspacePath) {
|
|
2331
|
+
try {
|
|
2332
|
+
return await getWorkspaceStatus(
|
|
2333
|
+
this.workspaceCwd,
|
|
2334
|
+
workspacePath,
|
|
2335
|
+
this.getRealWorkspaceCwd()
|
|
2336
|
+
);
|
|
2337
|
+
} catch (error) {
|
|
2338
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
2339
|
+
throw new SessionArtifactValidationError(
|
|
2340
|
+
`workspacePath could not be inspected: ${reason}`,
|
|
2341
|
+
"workspacePath"
|
|
2342
|
+
);
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
async refreshWorkspaceStatus(artifact, options) {
|
|
2346
|
+
if (!artifact.workspacePath) {
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
try {
|
|
2350
|
+
const status = await getWorkspaceStatus(
|
|
2351
|
+
this.workspaceCwd,
|
|
2352
|
+
artifact.workspacePath,
|
|
2353
|
+
this.getRealWorkspaceCwd()
|
|
2354
|
+
);
|
|
2355
|
+
artifact.status = status.status;
|
|
2356
|
+
artifact.sizeBytes = status.sizeBytes;
|
|
2357
|
+
if (status.escaped) {
|
|
2358
|
+
artifact.status = "missing";
|
|
2359
|
+
artifact.sizeBytes = void 0;
|
|
2360
|
+
delete artifact.workspacePath;
|
|
2361
|
+
}
|
|
2362
|
+
artifact.lastStatAt = options.now ?? Date.now();
|
|
2363
|
+
} catch (error) {
|
|
2364
|
+
writeStderrLine(
|
|
2365
|
+
`[artifacts] session=${this.sessionId} action=status_refresh_failed artifactId=${artifact.id} reason=${JSON.stringify(
|
|
2366
|
+
error instanceof Error ? error.message : String(error)
|
|
2367
|
+
)}`
|
|
2368
|
+
);
|
|
2369
|
+
if (options.onError === "missing") {
|
|
2370
|
+
artifact.status = "missing";
|
|
2371
|
+
artifact.sizeBytes = void 0;
|
|
2372
|
+
artifact.lastStatAt = options.now ?? Date.now();
|
|
2373
|
+
}
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
getRealWorkspaceCwd() {
|
|
2378
|
+
if (!this.realWorkspaceCwdPromise) {
|
|
2379
|
+
const promise = fs2.realpath(this.workspaceCwd).catch((error) => {
|
|
2380
|
+
if (this.realWorkspaceCwdPromise === promise) {
|
|
2381
|
+
this.realWorkspaceCwdPromise = void 0;
|
|
2382
|
+
}
|
|
2383
|
+
throw error;
|
|
2384
|
+
});
|
|
2385
|
+
this.realWorkspaceCwdPromise = promise;
|
|
2386
|
+
}
|
|
2387
|
+
return this.realWorkspaceCwdPromise;
|
|
2388
|
+
}
|
|
2389
|
+
async evictOverflow(createdIds, changes) {
|
|
2390
|
+
const removed = [];
|
|
2391
|
+
if (this.artifacts.size <= this.maxArtifacts) {
|
|
2392
|
+
return removed;
|
|
2393
|
+
}
|
|
2394
|
+
const createdInThisBatch = new Set(createdIds);
|
|
2395
|
+
const candidates = Array.from(this.artifacts.values()).filter(
|
|
2396
|
+
(artifact) => !createdInThisBatch.has(artifact.id)
|
|
2397
|
+
);
|
|
2398
|
+
const now = Date.now();
|
|
2399
|
+
const staleWorkspaceCandidates = candidates.filter((artifact) => artifact.workspacePath).filter((artifact) => shouldRefreshWorkspaceStatus(artifact, now));
|
|
2400
|
+
await runInBatches(
|
|
2401
|
+
staleWorkspaceCandidates,
|
|
2402
|
+
WORKSPACE_STATUS_REFRESH_BATCH_SIZE,
|
|
2403
|
+
(artifact) => this.refreshWorkspaceStatus(artifact, { onError: "preserve", now })
|
|
2404
|
+
);
|
|
2405
|
+
const sourceCounts = countByRetentionSource(this.artifacts.values());
|
|
2406
|
+
while (this.artifacts.size > this.maxArtifacts) {
|
|
2407
|
+
const artifact = selectEvictionCandidate(candidates, sourceCounts);
|
|
2408
|
+
if (!artifact) break;
|
|
2409
|
+
this.artifacts.delete(artifact.id);
|
|
2410
|
+
candidates.splice(candidates.indexOf(artifact), 1);
|
|
2411
|
+
sourceCounts[artifact.retentionSource]--;
|
|
2412
|
+
removePriorChange(changes, artifact.id);
|
|
2413
|
+
removed.push({
|
|
2414
|
+
action: "removed",
|
|
2415
|
+
artifactId: artifact.id,
|
|
2416
|
+
artifact: toPublicArtifact(artifact),
|
|
2417
|
+
reason: "eviction"
|
|
2418
|
+
});
|
|
2419
|
+
}
|
|
2420
|
+
const overflowCreated = Array.from(this.artifacts.values()).filter((artifact) => createdInThisBatch.has(artifact.id)).sort((a, b) => b.receivedSeq - a.receivedSeq);
|
|
2421
|
+
for (const artifact of overflowCreated) {
|
|
2422
|
+
if (this.artifacts.size <= this.maxArtifacts) {
|
|
2423
|
+
break;
|
|
2424
|
+
}
|
|
2425
|
+
this.artifacts.delete(artifact.id);
|
|
2426
|
+
writeStderrLine(
|
|
2427
|
+
`[artifacts] session=${this.sessionId} action=dropped reason="max artifacts exceeded" artifactId=${artifact.id}`
|
|
2428
|
+
);
|
|
2429
|
+
removePriorChange(changes, artifact.id);
|
|
2430
|
+
}
|
|
2431
|
+
return removed;
|
|
2432
|
+
}
|
|
2433
|
+
};
|
|
2434
|
+
function coalesceByIdentity(artifacts) {
|
|
2435
|
+
const byId = /* @__PURE__ */ new Map();
|
|
2436
|
+
for (const artifact of artifacts) {
|
|
2437
|
+
const existing = byId.get(artifact.id);
|
|
2438
|
+
if (!existing) {
|
|
2439
|
+
byId.set(artifact.id, artifact);
|
|
2440
|
+
continue;
|
|
2441
|
+
}
|
|
2442
|
+
byId.set(artifact.id, mergeBatchArtifact(existing, artifact));
|
|
2443
|
+
}
|
|
2444
|
+
return Array.from(byId.values()).sort(
|
|
2445
|
+
(a, b) => a.receivedSeq - b.receivedSeq
|
|
2446
|
+
);
|
|
2447
|
+
}
|
|
2448
|
+
__name(coalesceByIdentity, "coalesceByIdentity");
|
|
2449
|
+
function mergeBatchArtifact(existing, next) {
|
|
2450
|
+
const publishedUpgrade = existing.storage !== "published" && next.storage === "published" && next.trustedPublisher;
|
|
2451
|
+
if (publishedUpgrade) {
|
|
2452
|
+
const merged = {
|
|
2453
|
+
...existing,
|
|
2454
|
+
id: next.id,
|
|
2455
|
+
identityKey: next.identityKey,
|
|
2456
|
+
kind: next.kind,
|
|
2457
|
+
storage: "published",
|
|
2458
|
+
status: next.status,
|
|
2459
|
+
title: next.title,
|
|
2460
|
+
description: next.description,
|
|
2461
|
+
managedId: next.managedId ?? existing.managedId,
|
|
2462
|
+
url: next.url ?? existing.url,
|
|
2463
|
+
mimeType: next.mimeType ?? existing.mimeType,
|
|
2464
|
+
sizeBytes: next.sizeBytes ?? existing.sizeBytes,
|
|
2465
|
+
metadata: mergeMetadata(existing, next),
|
|
2466
|
+
trustedPublisher: true,
|
|
2467
|
+
createdAt: existing.createdAt,
|
|
2468
|
+
receivedSeq: existing.receivedSeq,
|
|
2469
|
+
retentionSource: existing.retentionSource,
|
|
2470
|
+
clientRetained: existing.clientRetained || next.clientRetained,
|
|
2471
|
+
lastStatAt: void 0
|
|
2472
|
+
};
|
|
2473
|
+
delete merged.workspacePath;
|
|
2474
|
+
return merged;
|
|
2475
|
+
}
|
|
2476
|
+
return {
|
|
2477
|
+
...existing,
|
|
2478
|
+
status: next.status,
|
|
2479
|
+
sizeBytes: mergeSizeBytes(existing, next),
|
|
2480
|
+
metadata: mergeMetadata(existing, next),
|
|
2481
|
+
clientRetained: existing.clientRetained || next.clientRetained,
|
|
2482
|
+
trustedPublisher: existing.trustedPublisher || next.trustedPublisher,
|
|
2483
|
+
lastStatAt: next.lastStatAt ?? existing.lastStatAt
|
|
2484
|
+
};
|
|
2485
|
+
}
|
|
2486
|
+
__name(mergeBatchArtifact, "mergeBatchArtifact");
|
|
2487
|
+
function mergeArtifact(existing, incoming) {
|
|
2488
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2489
|
+
const publishedUpgrade = existing.storage !== "published" && incoming.storage === "published" && incoming.trustedPublisher;
|
|
2490
|
+
const publishedRefresh = existing.storage === "published" && incoming.storage === "published" && incoming.trustedPublisher && incoming.managedId !== void 0 && incoming.managedId === existing.managedId;
|
|
2491
|
+
const publishedUpdate = publishedUpgrade || publishedRefresh;
|
|
2492
|
+
const next = {
|
|
2493
|
+
...existing,
|
|
2494
|
+
id: publishedUpdate ? incoming.id : existing.id,
|
|
2495
|
+
identityKey: publishedUpdate ? incoming.identityKey : existing.identityKey,
|
|
2496
|
+
kind: publishedUpdate ? incoming.kind : existing.kind,
|
|
2497
|
+
storage: publishedUpgrade ? "published" : existing.storage,
|
|
2498
|
+
status: existing.storage === "published" && !publishedUpdate ? existing.status : incoming.status,
|
|
2499
|
+
managedId: publishedUpdate ? incoming.managedId ?? existing.managedId : existing.managedId,
|
|
2500
|
+
url: publishedUpdate ? incoming.url ?? existing.url : existing.url,
|
|
2501
|
+
workspacePath: publishedUpdate || existing.storage === "published" ? void 0 : existing.workspacePath ?? incoming.workspacePath,
|
|
2502
|
+
mimeType: publishedUpdate ? incoming.mimeType ?? existing.mimeType : existing.mimeType,
|
|
2503
|
+
sizeBytes: existing.storage === "published" && !publishedUpdate ? existing.sizeBytes : mergeSizeBytes(existing, incoming),
|
|
2504
|
+
metadata: existing.storage === "published" && !publishedUpdate ? existing.metadata : mergeMetadata(existing, incoming),
|
|
2505
|
+
source: existing.source,
|
|
2506
|
+
retentionSource: existing.retentionSource,
|
|
2507
|
+
trustedPublisher: existing.trustedPublisher || incoming.trustedPublisher,
|
|
2508
|
+
clientRetained: existing.clientRetained || incoming.clientRetained,
|
|
2509
|
+
lastStatAt: publishedUpdate || existing.storage === "published" ? void 0 : incoming.lastStatAt ?? existing.lastStatAt,
|
|
2510
|
+
updatedAt: existing.updatedAt
|
|
2511
|
+
};
|
|
2512
|
+
if (publishedUpdate) {
|
|
2513
|
+
next.title = incoming.title;
|
|
2514
|
+
next.description = incoming.description;
|
|
2515
|
+
delete next.workspacePath;
|
|
2516
|
+
}
|
|
2517
|
+
const changed = !publicArtifactsEqual(
|
|
2518
|
+
toPublicArtifact(existing),
|
|
2519
|
+
toPublicArtifact(next)
|
|
2520
|
+
);
|
|
2521
|
+
if (changed) {
|
|
2522
|
+
next.updatedAt = now;
|
|
2523
|
+
}
|
|
2524
|
+
return { artifact: changed ? next : existing, changed };
|
|
2525
|
+
}
|
|
2526
|
+
__name(mergeArtifact, "mergeArtifact");
|
|
2527
|
+
function publicArtifactsEqual(a, b) {
|
|
2528
|
+
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;
|
|
2529
|
+
}
|
|
2530
|
+
__name(publicArtifactsEqual, "publicArtifactsEqual");
|
|
2531
|
+
function metadataEqual(a, b) {
|
|
2532
|
+
if (a === b) return true;
|
|
2533
|
+
if (!a || !b) return false;
|
|
2534
|
+
const aKeys = Object.keys(a);
|
|
2535
|
+
const bKeys = Object.keys(b);
|
|
2536
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
2537
|
+
return aKeys.every((key) => Object.hasOwn(b, key) && a[key] === b[key]);
|
|
2538
|
+
}
|
|
2539
|
+
__name(metadataEqual, "metadataEqual");
|
|
2540
|
+
function mergeSizeBytes(existing, incoming) {
|
|
2541
|
+
if (incoming.sizeBytes !== void 0) {
|
|
2542
|
+
return incoming.sizeBytes;
|
|
2543
|
+
}
|
|
2544
|
+
if (incoming.workspacePath && incoming.status === "missing") {
|
|
2545
|
+
return void 0;
|
|
2546
|
+
}
|
|
2547
|
+
return existing.sizeBytes;
|
|
2548
|
+
}
|
|
2549
|
+
__name(mergeSizeBytes, "mergeSizeBytes");
|
|
2550
|
+
function mergeMetadata(existing, incoming) {
|
|
2551
|
+
if (!incoming.metadata || incoming.source === "hook" || incoming.source !== existing.source) {
|
|
2552
|
+
return existing.metadata;
|
|
2553
|
+
}
|
|
2554
|
+
const merged = { ...existing.metadata ?? {} };
|
|
2555
|
+
let changed = false;
|
|
2556
|
+
for (const [key, value] of Object.entries(incoming.metadata)) {
|
|
2557
|
+
if (!Object.hasOwn(merged, key)) {
|
|
2558
|
+
merged[key] = value;
|
|
2559
|
+
changed = true;
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
if (!changed) {
|
|
2563
|
+
return existing.metadata;
|
|
2564
|
+
}
|
|
2565
|
+
if (!isMetadataWithinLimit(merged)) {
|
|
2566
|
+
writeStderrLine(
|
|
2567
|
+
`[artifacts] action=metadata_merge_dropped artifactId=${incoming.id} reason="metadata limit exceeded"`
|
|
2568
|
+
);
|
|
2569
|
+
return existing.metadata;
|
|
2570
|
+
}
|
|
2571
|
+
return merged;
|
|
2572
|
+
}
|
|
2573
|
+
__name(mergeMetadata, "mergeMetadata");
|
|
2574
|
+
function isMetadataWithinLimit(metadata) {
|
|
2575
|
+
return Buffer.byteLength(JSON.stringify(metadata), "utf8") <= 4096;
|
|
2576
|
+
}
|
|
2577
|
+
__name(isMetadataWithinLimit, "isMetadataWithinLimit");
|
|
2578
|
+
function countByRetentionSource(artifacts) {
|
|
2579
|
+
const counts = {
|
|
2580
|
+
tool: 0,
|
|
2581
|
+
client: 0,
|
|
2582
|
+
hook: 0
|
|
2583
|
+
};
|
|
2584
|
+
for (const artifact of artifacts) {
|
|
2585
|
+
counts[artifact.retentionSource]++;
|
|
2586
|
+
}
|
|
2587
|
+
return counts;
|
|
2588
|
+
}
|
|
2589
|
+
__name(countByRetentionSource, "countByRetentionSource");
|
|
2590
|
+
function shouldRefreshWorkspaceStatus(artifact, now) {
|
|
2591
|
+
return artifact.lastStatAt === void 0 || now - artifact.lastStatAt >= WORKSPACE_STATUS_REFRESH_TTL_MS;
|
|
2592
|
+
}
|
|
2593
|
+
__name(shouldRefreshWorkspaceStatus, "shouldRefreshWorkspaceStatus");
|
|
2594
|
+
function selectEvictionCandidate(candidates, sourceCounts) {
|
|
2595
|
+
return oldest(
|
|
2596
|
+
candidates,
|
|
2597
|
+
(artifact) => artifact.status === "missing" && !artifact.clientRetained
|
|
2598
|
+
) ?? oldest(
|
|
2599
|
+
candidates,
|
|
2600
|
+
(artifact) => !artifact.clientRetained && sourceCounts[artifact.retentionSource] > SOURCE_RESERVATIONS[artifact.retentionSource]
|
|
2601
|
+
) ?? oldest(candidates, (artifact) => !artifact.clientRetained) ?? oldest(candidates);
|
|
2602
|
+
}
|
|
2603
|
+
__name(selectEvictionCandidate, "selectEvictionCandidate");
|
|
2604
|
+
function oldest(artifacts, predicate = () => true) {
|
|
2605
|
+
let selected;
|
|
2606
|
+
for (const artifact of artifacts) {
|
|
2607
|
+
if (!predicate(artifact)) {
|
|
2608
|
+
continue;
|
|
2609
|
+
}
|
|
2610
|
+
if (!selected || compareOldest(artifact, selected) < 0) {
|
|
2611
|
+
selected = artifact;
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
return selected;
|
|
2615
|
+
}
|
|
2616
|
+
__name(oldest, "oldest");
|
|
2617
|
+
function compareOldest(a, b) {
|
|
2618
|
+
const created = a.createdAt.localeCompare(b.createdAt);
|
|
2619
|
+
if (created !== 0) return created;
|
|
2620
|
+
return a.insertSeq - b.insertSeq;
|
|
2621
|
+
}
|
|
2622
|
+
__name(compareOldest, "compareOldest");
|
|
2623
|
+
function removePriorChange(changes, artifactId) {
|
|
2624
|
+
const index = changes.findIndex((change) => change.artifactId === artifactId);
|
|
2625
|
+
if (index >= 0) {
|
|
2626
|
+
changes.splice(index, 1);
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
__name(removePriorChange, "removePriorChange");
|
|
2630
|
+
function toPublicArtifact(artifact) {
|
|
2631
|
+
const {
|
|
2632
|
+
id,
|
|
2633
|
+
kind,
|
|
2634
|
+
storage,
|
|
2635
|
+
source,
|
|
2636
|
+
status,
|
|
2637
|
+
title,
|
|
2638
|
+
description,
|
|
2639
|
+
workspacePath,
|
|
2640
|
+
managedId,
|
|
2641
|
+
url,
|
|
2642
|
+
mimeType,
|
|
2643
|
+
sizeBytes,
|
|
2644
|
+
metadata,
|
|
2645
|
+
clientRetained,
|
|
2646
|
+
createdAt,
|
|
2647
|
+
updatedAt,
|
|
2648
|
+
toolCallId,
|
|
2649
|
+
toolName,
|
|
2650
|
+
hookEventName,
|
|
2651
|
+
clientId
|
|
2652
|
+
} = artifact;
|
|
2653
|
+
return {
|
|
2654
|
+
id,
|
|
2655
|
+
kind,
|
|
2656
|
+
storage,
|
|
2657
|
+
source,
|
|
2658
|
+
status,
|
|
2659
|
+
title,
|
|
2660
|
+
...description ? { description } : {},
|
|
2661
|
+
...workspacePath ? { workspacePath } : {},
|
|
2662
|
+
...managedId ? { managedId } : {},
|
|
2663
|
+
...url ? { url } : {},
|
|
2664
|
+
...mimeType ? { mimeType } : {},
|
|
2665
|
+
...sizeBytes !== void 0 ? { sizeBytes } : {},
|
|
2666
|
+
...metadata ? { metadata } : {},
|
|
2667
|
+
clientRetained,
|
|
2668
|
+
createdAt,
|
|
2669
|
+
updatedAt,
|
|
2670
|
+
...toolCallId ? { toolCallId } : {},
|
|
2671
|
+
...toolName ? { toolName } : {},
|
|
2672
|
+
...hookEventName ? { hookEventName } : {},
|
|
2673
|
+
...clientId ? { clientId } : {}
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
__name(toPublicArtifact, "toPublicArtifact");
|
|
2677
|
+
function inferStorage(requested, locators) {
|
|
2678
|
+
if (requested !== void 0 && typeof requested !== "string") {
|
|
2679
|
+
throw new SessionArtifactValidationError(
|
|
2680
|
+
"storage must be a string",
|
|
2681
|
+
"storage"
|
|
2682
|
+
);
|
|
2683
|
+
}
|
|
2684
|
+
if (requested) {
|
|
2685
|
+
if (requested !== "workspace" && requested !== "external_url" && requested !== "managed" && requested !== "published") {
|
|
2686
|
+
throw new SessionArtifactValidationError(
|
|
2687
|
+
"storage must be workspace, external_url, managed, or published",
|
|
2688
|
+
"storage"
|
|
2689
|
+
);
|
|
2690
|
+
}
|
|
2691
|
+
return requested;
|
|
2692
|
+
}
|
|
2693
|
+
if (locators.workspacePath) return "workspace";
|
|
2694
|
+
if (locators.managedId) return "managed";
|
|
2695
|
+
if (locators.url && locators.trustedPublisher) return "published";
|
|
2696
|
+
return "external_url";
|
|
2697
|
+
}
|
|
2698
|
+
__name(inferStorage, "inferStorage");
|
|
2699
|
+
function normalizeKind(kind) {
|
|
2700
|
+
if (kind === "file" || kind === "link" || kind === "html" || kind === "image" || kind === "video" || kind === "audio" || kind === "pdf" || kind === "notebook" || kind === "other") {
|
|
2701
|
+
return kind;
|
|
2702
|
+
}
|
|
2703
|
+
throw new SessionArtifactValidationError(
|
|
2704
|
+
"kind must be a supported artifact kind",
|
|
2705
|
+
"kind"
|
|
2706
|
+
);
|
|
2707
|
+
}
|
|
2708
|
+
__name(normalizeKind, "normalizeKind");
|
|
2709
|
+
function validateLocator(storage, locators) {
|
|
2710
|
+
if (storage === "published") {
|
|
2711
|
+
if (!locators.trustedPublisher) {
|
|
2712
|
+
throw new SessionArtifactValidationError(
|
|
2713
|
+
"published artifacts are reserved for trusted publishers",
|
|
2714
|
+
"storage"
|
|
2715
|
+
);
|
|
2716
|
+
}
|
|
2717
|
+
if (!locators.url) {
|
|
2718
|
+
throw new SessionArtifactValidationError(
|
|
2719
|
+
"published artifacts require url",
|
|
2720
|
+
"url"
|
|
2721
|
+
);
|
|
2722
|
+
}
|
|
2723
|
+
if (locators.workspacePath) {
|
|
2724
|
+
throw new SessionArtifactValidationError(
|
|
2725
|
+
"published artifacts cannot include workspacePath",
|
|
2726
|
+
"workspacePath"
|
|
2727
|
+
);
|
|
2728
|
+
}
|
|
2729
|
+
return;
|
|
2730
|
+
}
|
|
2731
|
+
const locatorCount = [
|
|
2732
|
+
locators.workspacePath,
|
|
2733
|
+
locators.managedId,
|
|
2734
|
+
locators.url
|
|
2735
|
+
].filter(Boolean).length;
|
|
2736
|
+
if (locatorCount !== 1) {
|
|
2737
|
+
throw new SessionArtifactValidationError(
|
|
2738
|
+
"provide exactly one of workspacePath, managedId, or url"
|
|
2739
|
+
);
|
|
2740
|
+
}
|
|
2741
|
+
if (storage === "workspace" && !locators.workspacePath) {
|
|
2742
|
+
throw new SessionArtifactValidationError(
|
|
2743
|
+
"workspace storage requires workspacePath",
|
|
2744
|
+
"workspacePath"
|
|
2745
|
+
);
|
|
2746
|
+
}
|
|
2747
|
+
if (storage === "managed" && !locators.managedId) {
|
|
2748
|
+
throw new SessionArtifactValidationError(
|
|
2749
|
+
"managed storage requires managedId",
|
|
2750
|
+
"managedId"
|
|
2751
|
+
);
|
|
2752
|
+
}
|
|
2753
|
+
if (storage === "external_url" && !locators.url) {
|
|
2754
|
+
throw new SessionArtifactValidationError(
|
|
2755
|
+
"external_url storage requires url",
|
|
2756
|
+
"url"
|
|
2757
|
+
);
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
__name(validateLocator, "validateLocator");
|
|
2761
|
+
function buildIdentityKey(input) {
|
|
2762
|
+
if (input.workspacePath) return `workspace:${input.workspacePath}`;
|
|
2763
|
+
if (input.managedId) return `managed:${input.managedId}`;
|
|
2764
|
+
if (input.url) return `url:${input.url}`;
|
|
2765
|
+
throw new SessionArtifactValidationError(
|
|
2766
|
+
"artifact identity requires workspacePath, managedId, or url"
|
|
2767
|
+
);
|
|
2768
|
+
}
|
|
2769
|
+
__name(buildIdentityKey, "buildIdentityKey");
|
|
2770
|
+
function stableArtifactId(sessionId, identityKey) {
|
|
2771
|
+
return createHash("sha256").update(`${sessionId}:${identityKey}`).digest("hex").slice(0, 16);
|
|
2772
|
+
}
|
|
2773
|
+
__name(stableArtifactId, "stableArtifactId");
|
|
2774
|
+
function managedIdForWorkspacePath(workspaceCwd, workspacePath) {
|
|
2775
|
+
return createHash("sha1").update(path2.resolve(workspaceCwd, workspacePath)).digest("hex").slice(0, 16);
|
|
2776
|
+
}
|
|
2777
|
+
__name(managedIdForWorkspacePath, "managedIdForWorkspacePath");
|
|
2778
|
+
function normalizeString(value, field, maxLength, required) {
|
|
2779
|
+
if (value === void 0 || value === null) {
|
|
2780
|
+
if (required) {
|
|
2781
|
+
throw new SessionArtifactValidationError(`${field} is required`, field);
|
|
2782
|
+
}
|
|
2783
|
+
return void 0;
|
|
2784
|
+
}
|
|
2785
|
+
if (typeof value !== "string") {
|
|
2786
|
+
throw new SessionArtifactValidationError(
|
|
2787
|
+
`${field} must be a string`,
|
|
2788
|
+
field
|
|
2789
|
+
);
|
|
2790
|
+
}
|
|
2791
|
+
const trimmed = value.trim();
|
|
2792
|
+
if (!trimmed) {
|
|
2793
|
+
if (required) {
|
|
2794
|
+
throw new SessionArtifactValidationError(`${field} is required`, field);
|
|
2795
|
+
}
|
|
2796
|
+
return void 0;
|
|
2797
|
+
}
|
|
2798
|
+
if (trimmed.length > maxLength) {
|
|
2799
|
+
throw new SessionArtifactValidationError(
|
|
2800
|
+
`${field} exceeds ${maxLength} characters`,
|
|
2801
|
+
field
|
|
2802
|
+
);
|
|
2803
|
+
}
|
|
2804
|
+
if (hasControlCharacter(trimmed, field === "description")) {
|
|
2805
|
+
throw new SessionArtifactValidationError(
|
|
2806
|
+
`${field} contains control characters`,
|
|
2807
|
+
field
|
|
2808
|
+
);
|
|
2809
|
+
}
|
|
2810
|
+
if (isDisplayField(field) && hasUnsafeDisplayPayload(trimmed)) {
|
|
2811
|
+
throw new SessionArtifactValidationError(
|
|
2812
|
+
`${field} contains unsafe markup`,
|
|
2813
|
+
field
|
|
2814
|
+
);
|
|
2815
|
+
}
|
|
2816
|
+
return trimmed;
|
|
2817
|
+
}
|
|
2818
|
+
__name(normalizeString, "normalizeString");
|
|
2819
|
+
function normalizeManagedId(value) {
|
|
2820
|
+
const managedId = normalizeString(value, "managedId", 200, false);
|
|
2821
|
+
if (!managedId) return void 0;
|
|
2822
|
+
if (managedId.includes("/") || managedId.includes("\\") || managedId.includes("..") || path2.isAbsolute(managedId) || path2.win32.isAbsolute(managedId)) {
|
|
2823
|
+
throw new SessionArtifactValidationError(
|
|
2824
|
+
"managedId must be an opaque managed resource id",
|
|
2825
|
+
"managedId"
|
|
2826
|
+
);
|
|
2827
|
+
}
|
|
2828
|
+
return managedId;
|
|
2829
|
+
}
|
|
2830
|
+
__name(normalizeManagedId, "normalizeManagedId");
|
|
2831
|
+
function isDisplayField(field) {
|
|
2832
|
+
return field === "title" || field === "description" || field === "mimeType" || field === "workspacePath" || field === "managedId";
|
|
2833
|
+
}
|
|
2834
|
+
__name(isDisplayField, "isDisplayField");
|
|
2835
|
+
function hasControlCharacter(value, allowLineWhitespace = false) {
|
|
2836
|
+
for (let i = 0; i < value.length; i++) {
|
|
2837
|
+
const code = value.charCodeAt(i);
|
|
2838
|
+
if (allowLineWhitespace && (code === 9 || code === 10 || code === 13)) {
|
|
2839
|
+
continue;
|
|
2840
|
+
}
|
|
2841
|
+
if (code <= 31 || code === 127 || code >= 8203 && code <= 8207 || code === 8232 || code === 8233 || code >= 8234 && code <= 8238 || code >= 8294 && code <= 8297 || code === 65279) {
|
|
2842
|
+
return true;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
return false;
|
|
2846
|
+
}
|
|
2847
|
+
__name(hasControlCharacter, "hasControlCharacter");
|
|
2848
|
+
function hasUnsafeDisplayPayload(value) {
|
|
2849
|
+
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(
|
|
2850
|
+
value
|
|
2851
|
+
) || /(?:^|[\s"'`<])on[a-z][a-z0-9-]*\s*=/i.test(value);
|
|
2852
|
+
}
|
|
2853
|
+
__name(hasUnsafeDisplayPayload, "hasUnsafeDisplayPayload");
|
|
2854
|
+
function normalizeWorkspacePath(raw, workspaceCwd) {
|
|
2855
|
+
const trimmed = normalizeString(raw, "workspacePath", 500, true);
|
|
2856
|
+
if (path2.isAbsolute(trimmed)) {
|
|
2857
|
+
throw new SessionArtifactValidationError(
|
|
2858
|
+
"workspacePath must be relative to the workspace",
|
|
2859
|
+
"workspacePath"
|
|
2860
|
+
);
|
|
2861
|
+
}
|
|
2862
|
+
const absolute = path2.resolve(workspaceCwd, trimmed);
|
|
2863
|
+
const relative = path2.relative(workspaceCwd, absolute);
|
|
2864
|
+
if (!relative || isOutsidePath(relative)) {
|
|
2865
|
+
throw new SessionArtifactValidationError(
|
|
2866
|
+
"workspacePath must stay inside the workspace",
|
|
2867
|
+
"workspacePath"
|
|
2868
|
+
);
|
|
2869
|
+
}
|
|
2870
|
+
return relative.split(path2.sep).join("/");
|
|
2871
|
+
}
|
|
2872
|
+
__name(normalizeWorkspacePath, "normalizeWorkspacePath");
|
|
2873
|
+
function normalizeArtifactUrl(raw, allowFile) {
|
|
2874
|
+
const trimmed = normalizeString(raw, "url", 2048, true);
|
|
2875
|
+
let parsed;
|
|
2876
|
+
try {
|
|
2877
|
+
parsed = new URL(trimmed);
|
|
2878
|
+
} catch {
|
|
2879
|
+
throw new SessionArtifactValidationError("url must be valid", "url");
|
|
2880
|
+
}
|
|
2881
|
+
if (parsed.username || parsed.password) {
|
|
2882
|
+
throw new SessionArtifactValidationError(
|
|
2883
|
+
"url must not include credentials",
|
|
2884
|
+
"url"
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" && !(allowFile && parsed.protocol === "file:")) {
|
|
2888
|
+
throw new SessionArtifactValidationError(
|
|
2889
|
+
allowFile ? "url must use http, https, or file" : "url must use http or https",
|
|
2890
|
+
"url"
|
|
2891
|
+
);
|
|
2892
|
+
}
|
|
2893
|
+
return parsed.href;
|
|
2894
|
+
}
|
|
2895
|
+
__name(normalizeArtifactUrl, "normalizeArtifactUrl");
|
|
2896
|
+
function normalizeMetadata(metadata) {
|
|
2897
|
+
if (metadata === void 0) {
|
|
2898
|
+
return void 0;
|
|
2899
|
+
}
|
|
2900
|
+
if (typeof metadata !== "object" || metadata === null || Array.isArray(metadata)) {
|
|
2901
|
+
throw new SessionArtifactValidationError(
|
|
2902
|
+
"metadata must be an object",
|
|
2903
|
+
"metadata"
|
|
2904
|
+
);
|
|
2905
|
+
}
|
|
2906
|
+
const normalized = {};
|
|
2907
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
2908
|
+
if (!key) {
|
|
2909
|
+
throw new SessionArtifactValidationError(
|
|
2910
|
+
"metadata keys must not be empty",
|
|
2911
|
+
"metadata"
|
|
2912
|
+
);
|
|
2913
|
+
}
|
|
2914
|
+
if (key.length > 120) {
|
|
2915
|
+
throw new SessionArtifactValidationError(
|
|
2916
|
+
"metadata keys must be 120 characters or fewer",
|
|
2917
|
+
"metadata"
|
|
2918
|
+
);
|
|
2919
|
+
}
|
|
2920
|
+
if (hasControlCharacter(key) || hasUnsafeDisplayPayload(key)) {
|
|
2921
|
+
throw new SessionArtifactValidationError(
|
|
2922
|
+
"metadata keys contain unsafe content",
|
|
2923
|
+
"metadata"
|
|
2924
|
+
);
|
|
2925
|
+
}
|
|
2926
|
+
if (value !== null && typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
|
|
2927
|
+
throw new SessionArtifactValidationError(
|
|
2928
|
+
"metadata values must be primitive",
|
|
2929
|
+
"metadata"
|
|
2930
|
+
);
|
|
2931
|
+
}
|
|
2932
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
2933
|
+
throw new SessionArtifactValidationError(
|
|
2934
|
+
"metadata numbers must be finite",
|
|
2935
|
+
"metadata"
|
|
2936
|
+
);
|
|
2937
|
+
}
|
|
2938
|
+
if (typeof value === "string" && (hasControlCharacter(value) || hasUnsafeDisplayPayload(value))) {
|
|
2939
|
+
throw new SessionArtifactValidationError(
|
|
2940
|
+
"metadata string values contain unsafe content",
|
|
2941
|
+
"metadata"
|
|
2942
|
+
);
|
|
2943
|
+
}
|
|
2944
|
+
normalized[key] = value;
|
|
2945
|
+
}
|
|
2946
|
+
if (Object.keys(normalized).length === 0) {
|
|
2947
|
+
return void 0;
|
|
2948
|
+
}
|
|
2949
|
+
if (Buffer.byteLength(JSON.stringify(normalized), "utf8") > 4096) {
|
|
2950
|
+
throw new SessionArtifactValidationError(
|
|
2951
|
+
"metadata must be 4096 bytes or fewer",
|
|
2952
|
+
"metadata"
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
return normalized;
|
|
2956
|
+
}
|
|
2957
|
+
__name(normalizeMetadata, "normalizeMetadata");
|
|
2958
|
+
function normalizeSizeBytes(value) {
|
|
2959
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
2960
|
+
throw new SessionArtifactValidationError(
|
|
2961
|
+
"sizeBytes must be a non-negative safe integer",
|
|
2962
|
+
"sizeBytes"
|
|
2963
|
+
);
|
|
2964
|
+
}
|
|
2965
|
+
return value;
|
|
2966
|
+
}
|
|
2967
|
+
__name(normalizeSizeBytes, "normalizeSizeBytes");
|
|
2968
|
+
function inferKind(input) {
|
|
2969
|
+
if (input.storage === "published") return "html";
|
|
2970
|
+
if (input.url) return "link";
|
|
2971
|
+
const ext = input.workspacePath ? path2.extname(input.workspacePath).toLowerCase() : "";
|
|
2972
|
+
if (ext === ".html" || ext === ".htm") return "html";
|
|
2973
|
+
if ([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"].includes(ext)) {
|
|
2974
|
+
return "image";
|
|
2975
|
+
}
|
|
2976
|
+
if ([".mp4", ".mov", ".webm"].includes(ext)) return "video";
|
|
2977
|
+
if ([".mp3", ".wav", ".m4a", ".ogg"].includes(ext)) return "audio";
|
|
2978
|
+
if (ext === ".pdf") return "pdf";
|
|
2979
|
+
if (ext === ".ipynb") return "notebook";
|
|
2980
|
+
return input.workspacePath ? "file" : "other";
|
|
2981
|
+
}
|
|
2982
|
+
__name(inferKind, "inferKind");
|
|
2983
|
+
async function getWorkspaceStatus(workspaceCwd, workspacePath, realWorkspaceCwd) {
|
|
2984
|
+
const absolutePath = path2.resolve(workspaceCwd, workspacePath);
|
|
2985
|
+
const realWorkspace = await realWorkspaceCwd;
|
|
2986
|
+
try {
|
|
2987
|
+
const realPath = await fs2.realpath(absolutePath);
|
|
2988
|
+
const relative = path2.relative(realWorkspace, realPath);
|
|
2989
|
+
if (!relative || isOutsidePath(relative)) {
|
|
2990
|
+
return { status: "missing", escaped: true };
|
|
2991
|
+
}
|
|
2992
|
+
const stat = await fs2.stat(realPath);
|
|
2993
|
+
return {
|
|
2994
|
+
status: "available",
|
|
2995
|
+
...stat.isFile() ? { sizeBytes: stat.size } : {}
|
|
2996
|
+
};
|
|
2997
|
+
} catch (error) {
|
|
2998
|
+
if (!isNotFoundError(error)) {
|
|
2999
|
+
throw error;
|
|
3000
|
+
}
|
|
3001
|
+
if (await danglingSymlinkEscapesWorkspace(absolutePath, realWorkspace)) {
|
|
3002
|
+
return { status: "missing", escaped: true };
|
|
3003
|
+
}
|
|
3004
|
+
return { status: "missing" };
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
__name(getWorkspaceStatus, "getWorkspaceStatus");
|
|
3008
|
+
async function danglingSymlinkEscapesWorkspace(absolutePath, realWorkspace) {
|
|
3009
|
+
try {
|
|
3010
|
+
const stat = await fs2.lstat(absolutePath);
|
|
3011
|
+
if (!stat.isSymbolicLink()) {
|
|
3012
|
+
return false;
|
|
3013
|
+
}
|
|
3014
|
+
const target = await fs2.readlink(absolutePath);
|
|
3015
|
+
const parent = await fs2.realpath(path2.dirname(absolutePath));
|
|
3016
|
+
const targetPath = path2.resolve(parent, target);
|
|
3017
|
+
return isOutsidePath(path2.relative(realWorkspace, targetPath));
|
|
3018
|
+
} catch (error) {
|
|
3019
|
+
if (isNotFoundError(error)) {
|
|
3020
|
+
return false;
|
|
3021
|
+
}
|
|
3022
|
+
throw error;
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
__name(danglingSymlinkEscapesWorkspace, "danglingSymlinkEscapesWorkspace");
|
|
3026
|
+
async function runInBatches(items, batchSize, fn) {
|
|
3027
|
+
for (let index = 0; index < items.length; index += batchSize) {
|
|
3028
|
+
await Promise.all(items.slice(index, index + batchSize).map(fn));
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
__name(runInBatches, "runInBatches");
|
|
3032
|
+
function isNotFoundError(error) {
|
|
3033
|
+
if (typeof error !== "object" || error === null || !("code" in error)) {
|
|
3034
|
+
return false;
|
|
3035
|
+
}
|
|
3036
|
+
const code = error.code;
|
|
3037
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
3038
|
+
}
|
|
3039
|
+
__name(isNotFoundError, "isNotFoundError");
|
|
3040
|
+
function isOutsidePath(relative) {
|
|
3041
|
+
return relative === ".." || relative.startsWith(`..${path2.sep}`) || path2.isAbsolute(relative);
|
|
3042
|
+
}
|
|
3043
|
+
__name(isOutsidePath, "isOutsidePath");
|
|
3044
|
+
|
|
1861
3045
|
// packages/acp-bridge/src/bridge.ts
|
|
1862
3046
|
var NOOP_BRIDGE_TELEMETRY = {
|
|
1863
3047
|
captureContext: /* @__PURE__ */ __name(() => void 0, "captureContext"),
|
|
@@ -1927,6 +3111,62 @@ function parseWorkspaceMemoryRememberResult(response) {
|
|
|
1927
3111
|
};
|
|
1928
3112
|
}
|
|
1929
3113
|
__name(parseWorkspaceMemoryRememberResult, "parseWorkspaceMemoryRememberResult");
|
|
3114
|
+
function isBridgeAutoMemoryTopic(value) {
|
|
3115
|
+
return value === "user" || value === "feedback" || value === "project" || value === "reference";
|
|
3116
|
+
}
|
|
3117
|
+
__name(isBridgeAutoMemoryTopic, "isBridgeAutoMemoryTopic");
|
|
3118
|
+
function parseWorkspaceMemoryForgetMatch(value) {
|
|
3119
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3120
|
+
return null;
|
|
3121
|
+
}
|
|
3122
|
+
const record = value;
|
|
3123
|
+
if (!isBridgeAutoMemoryTopic(record["topic"]) || typeof record["summary"] !== "string" || typeof record["filePath"] !== "string") {
|
|
3124
|
+
return null;
|
|
3125
|
+
}
|
|
3126
|
+
return {
|
|
3127
|
+
topic: record["topic"],
|
|
3128
|
+
summary: record["summary"],
|
|
3129
|
+
filePath: record["filePath"]
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
__name(parseWorkspaceMemoryForgetMatch, "parseWorkspaceMemoryForgetMatch");
|
|
3133
|
+
function parseWorkspaceMemoryForgetResult(response) {
|
|
3134
|
+
if (response === null || typeof response !== "object" || Array.isArray(response)) {
|
|
3135
|
+
throw new Error("Malformed workspace memory forget response");
|
|
3136
|
+
}
|
|
3137
|
+
const record = response;
|
|
3138
|
+
const summary = record["summary"];
|
|
3139
|
+
const removedEntries = record["removedEntries"];
|
|
3140
|
+
const touchedTopics = record["touchedTopics"];
|
|
3141
|
+
const parsedRemovedEntries = Array.isArray(removedEntries) ? removedEntries.map(parseWorkspaceMemoryForgetMatch) : [];
|
|
3142
|
+
if (summary !== void 0 && typeof summary !== "string" || !Array.isArray(removedEntries) || parsedRemovedEntries.some((entry) => entry === null) || !Array.isArray(touchedTopics) || !touchedTopics.every(isBridgeAutoMemoryTopic)) {
|
|
3143
|
+
throw new Error("Malformed workspace memory forget response");
|
|
3144
|
+
}
|
|
3145
|
+
return {
|
|
3146
|
+
...summary === void 0 ? {} : { summary },
|
|
3147
|
+
removedEntries: parsedRemovedEntries,
|
|
3148
|
+
touchedTopics
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
__name(parseWorkspaceMemoryForgetResult, "parseWorkspaceMemoryForgetResult");
|
|
3152
|
+
function parseWorkspaceMemoryDreamResult(response) {
|
|
3153
|
+
if (response === null || typeof response !== "object" || Array.isArray(response)) {
|
|
3154
|
+
throw new Error("Malformed workspace memory dream response");
|
|
3155
|
+
}
|
|
3156
|
+
const record = response;
|
|
3157
|
+
const summary = record["summary"];
|
|
3158
|
+
const touchedTopics = record["touchedTopics"];
|
|
3159
|
+
const dedupedEntries = record["dedupedEntries"];
|
|
3160
|
+
if (summary !== void 0 && typeof summary !== "string" || !Array.isArray(touchedTopics) || !touchedTopics.every(isBridgeAutoMemoryTopic) || typeof dedupedEntries !== "number" || !Number.isFinite(dedupedEntries)) {
|
|
3161
|
+
throw new Error("Malformed workspace memory dream response");
|
|
3162
|
+
}
|
|
3163
|
+
return {
|
|
3164
|
+
...summary === void 0 ? {} : { summary },
|
|
3165
|
+
touchedTopics,
|
|
3166
|
+
dedupedEntries
|
|
3167
|
+
};
|
|
3168
|
+
}
|
|
3169
|
+
__name(parseWorkspaceMemoryDreamResult, "parseWorkspaceMemoryDreamResult");
|
|
1930
3170
|
function echoPromptToSessionBus(entry, req, originatorClientId) {
|
|
1931
3171
|
const prompt = req.prompt;
|
|
1932
3172
|
if (!Array.isArray(prompt) || prompt.length === 0) return;
|
|
@@ -2050,7 +3290,7 @@ function broadcastTurnError(entry, sessionId, err, promptId, originatorClientId)
|
|
|
2050
3290
|
}
|
|
2051
3291
|
}
|
|
2052
3292
|
__name(broadcastTurnError, "broadcastTurnError");
|
|
2053
|
-
function
|
|
3293
|
+
function hasControlCharacter2(value) {
|
|
2054
3294
|
for (let i = 0; i < value.length; i += 1) {
|
|
2055
3295
|
const code = value.charCodeAt(i);
|
|
2056
3296
|
if (code <= 31 || code === 127) {
|
|
@@ -2059,7 +3299,7 @@ function hasControlCharacter(value) {
|
|
|
2059
3299
|
}
|
|
2060
3300
|
return false;
|
|
2061
3301
|
}
|
|
2062
|
-
__name(
|
|
3302
|
+
__name(hasControlCharacter2, "hasControlCharacter");
|
|
2063
3303
|
function extractPromptText(prompt) {
|
|
2064
3304
|
if (!Array.isArray(prompt)) return "";
|
|
2065
3305
|
let hasImage = false;
|
|
@@ -2152,7 +3392,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2152
3392
|
} else {
|
|
2153
3393
|
maxPendingPromptsPerSession = maxPendingPromptsRaw;
|
|
2154
3394
|
}
|
|
2155
|
-
if (!
|
|
3395
|
+
if (!path3.isAbsolute(opts.boundWorkspace)) {
|
|
2156
3396
|
throw new TypeError(
|
|
2157
3397
|
`Invalid boundWorkspace: "${opts.boundWorkspace}". Must be an absolute path.`
|
|
2158
3398
|
);
|
|
@@ -2378,6 +3618,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2378
3618
|
},
|
|
2379
3619
|
async () => await channelFactory(boundWorkspace, childEnvOverrides)
|
|
2380
3620
|
);
|
|
3621
|
+
const sessionIds = /* @__PURE__ */ new Set();
|
|
2381
3622
|
const client = new BridgeClient(
|
|
2382
3623
|
// BfFut: ACP today carries a sessionId on every per-session
|
|
2383
3624
|
// notification / request, so the no-sessionId branch is
|
|
@@ -2427,14 +3668,15 @@ function createAcpSessionBridge(opts) {
|
|
|
2427
3668
|
// the per-WS-connection `ClientMcpRegistrar`. Omitted callers (tests,
|
|
2428
3669
|
// Mode A) never host a client MCP server, so the method stays
|
|
2429
3670
|
// unreachable.
|
|
2430
|
-
opts.clientMcpSender
|
|
3671
|
+
opts.clientMcpSender,
|
|
3672
|
+
(sessionId) => sessionIds.has(sessionId)
|
|
2431
3673
|
);
|
|
2432
3674
|
const connection = new ClientSideConnection(() => client, channel.stream);
|
|
2433
3675
|
const info = {
|
|
2434
3676
|
channel,
|
|
2435
3677
|
connection,
|
|
2436
3678
|
client,
|
|
2437
|
-
sessionIds
|
|
3679
|
+
sessionIds,
|
|
2438
3680
|
pendingRestoreIds: /* @__PURE__ */ new Set(),
|
|
2439
3681
|
sessionSpawnsInFlight: 0,
|
|
2440
3682
|
workspaceControlInFlight: 0,
|
|
@@ -2685,7 +3927,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2685
3927
|
return entry.transportClosedReject;
|
|
2686
3928
|
}, "getTransportClosedReject");
|
|
2687
3929
|
const resolveWorkspaceKey = /* @__PURE__ */ __name((workspaceCwd) => {
|
|
2688
|
-
if (!
|
|
3930
|
+
if (!path3.isAbsolute(workspaceCwd)) {
|
|
2689
3931
|
throw new Error(
|
|
2690
3932
|
`workspaceCwd must be an absolute path; got "${workspaceCwd}"`
|
|
2691
3933
|
);
|
|
@@ -2910,6 +4152,7 @@ function createAcpSessionBridge(opts) {
|
|
|
2910
4152
|
channel: ci.channel,
|
|
2911
4153
|
connection: ci.connection,
|
|
2912
4154
|
events,
|
|
4155
|
+
artifacts: new SessionArtifactStore({ sessionId, workspaceCwd }),
|
|
2913
4156
|
promptQueue: Promise.resolve(),
|
|
2914
4157
|
pendingPromptCount: 0,
|
|
2915
4158
|
pendingPromptList: [],
|
|
@@ -2933,6 +4176,34 @@ function createAcpSessionBridge(opts) {
|
|
|
2933
4176
|
ci.client.drainEarlyEvents(entry.sessionId, entry);
|
|
2934
4177
|
return entry;
|
|
2935
4178
|
}, "createSessionEntry");
|
|
4179
|
+
const publishArtifactChanges = /* @__PURE__ */ __name((entry, changes, originatorClientId) => {
|
|
4180
|
+
for (const change of changes) {
|
|
4181
|
+
entry.events.publish({
|
|
4182
|
+
type: "artifact_changed",
|
|
4183
|
+
data: { sessionId: entry.sessionId, change },
|
|
4184
|
+
...originatorClientId ? { originatorClientId } : {}
|
|
4185
|
+
});
|
|
4186
|
+
}
|
|
4187
|
+
}, "publishArtifactChanges");
|
|
4188
|
+
const makeClientArtifactInput = /* @__PURE__ */ __name((artifact, clientId) => {
|
|
4189
|
+
const input = {
|
|
4190
|
+
title: artifact.title,
|
|
4191
|
+
kind: artifact.kind,
|
|
4192
|
+
storage: artifact.storage,
|
|
4193
|
+
description: artifact.description,
|
|
4194
|
+
workspacePath: artifact.workspacePath,
|
|
4195
|
+
managedId: artifact.managedId,
|
|
4196
|
+
url: artifact.url,
|
|
4197
|
+
mimeType: artifact.mimeType,
|
|
4198
|
+
sizeBytes: artifact.sizeBytes,
|
|
4199
|
+
metadata: artifact.metadata,
|
|
4200
|
+
source: "client"
|
|
4201
|
+
};
|
|
4202
|
+
if (clientId) {
|
|
4203
|
+
input.clientId = clientId;
|
|
4204
|
+
}
|
|
4205
|
+
return input;
|
|
4206
|
+
}, "makeClientArtifactInput");
|
|
2936
4207
|
const seedSnapshotCaches = /* @__PURE__ */ __name((entry, resp) => {
|
|
2937
4208
|
const model = resp.models?.currentModelId;
|
|
2938
4209
|
if (typeof model === "string" && model.length > 0) {
|
|
@@ -3957,7 +5228,7 @@ function createAcpSessionBridge(opts) {
|
|
|
3957
5228
|
`must be a string of at most ${MAX_DISPLAY_NAME_LENGTH} characters`
|
|
3958
5229
|
);
|
|
3959
5230
|
}
|
|
3960
|
-
if (
|
|
5231
|
+
if (hasControlCharacter2(metadata.displayName)) {
|
|
3961
5232
|
throw new InvalidSessionMetadataError(
|
|
3962
5233
|
"displayName",
|
|
3963
5234
|
"must not contain control characters"
|
|
@@ -3999,8 +5270,30 @@ function createAcpSessionBridge(opts) {
|
|
|
3999
5270
|
}
|
|
4000
5271
|
return { displayName: entry.displayName };
|
|
4001
5272
|
},
|
|
5273
|
+
async getSessionArtifacts(sessionId) {
|
|
5274
|
+
const entry = byId.get(sessionId);
|
|
5275
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
5276
|
+
return entry.artifacts.list();
|
|
5277
|
+
},
|
|
5278
|
+
async addSessionArtifact(sessionId, artifact, context) {
|
|
5279
|
+
const entry = byId.get(sessionId);
|
|
5280
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
5281
|
+
const clientId = resolveTrustedClientId(entry, context?.clientId);
|
|
5282
|
+
const input = makeClientArtifactInput(artifact, clientId);
|
|
5283
|
+
const result = await entry.artifacts.upsertMany([input], { strict: true });
|
|
5284
|
+
publishArtifactChanges(entry, result.changes, clientId);
|
|
5285
|
+
return result;
|
|
5286
|
+
},
|
|
5287
|
+
async removeSessionArtifact(sessionId, artifactId, context) {
|
|
5288
|
+
const entry = byId.get(sessionId);
|
|
5289
|
+
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
5290
|
+
const clientId = resolveTrustedClientId(entry, context?.clientId);
|
|
5291
|
+
const result = await entry.artifacts.remove(artifactId, { clientId });
|
|
5292
|
+
publishArtifactChanges(entry, result.changes, clientId);
|
|
5293
|
+
return result;
|
|
5294
|
+
},
|
|
4002
5295
|
listWorkspaceSessions(workspaceCwd) {
|
|
4003
|
-
if (!
|
|
5296
|
+
if (!path3.isAbsolute(workspaceCwd)) return [];
|
|
4004
5297
|
const key = workspaceCwd === boundWorkspace ? boundWorkspace : canonicalizeWorkspace(workspaceCwd);
|
|
4005
5298
|
if (key !== boundWorkspace) return [];
|
|
4006
5299
|
const out = [];
|
|
@@ -4142,6 +5435,54 @@ function createAcpSessionBridge(opts) {
|
|
|
4142
5435
|
}
|
|
4143
5436
|
}
|
|
4144
5437
|
},
|
|
5438
|
+
async runWorkspaceMemoryForget(request) {
|
|
5439
|
+
const info = await ensureChannel();
|
|
5440
|
+
try {
|
|
5441
|
+
const response = await withWorkspaceControl(
|
|
5442
|
+
info,
|
|
5443
|
+
() => withTimeout(
|
|
5444
|
+
Promise.race([
|
|
5445
|
+
info.connection.extMethod(
|
|
5446
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryForget,
|
|
5447
|
+
{ ...request, cwd: boundWorkspace }
|
|
5448
|
+
),
|
|
5449
|
+
getChannelClosedReject(info)
|
|
5450
|
+
]),
|
|
5451
|
+
WORKSPACE_MEMORY_REMEMBER_TIMEOUT_MS,
|
|
5452
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryForget
|
|
5453
|
+
)
|
|
5454
|
+
);
|
|
5455
|
+
return parseWorkspaceMemoryForgetResult(response);
|
|
5456
|
+
} finally {
|
|
5457
|
+
if (hasNoChannelWork(info)) {
|
|
5458
|
+
await startIdleTimer(info, "workspace memory forget");
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
},
|
|
5462
|
+
async runWorkspaceMemoryDream() {
|
|
5463
|
+
const info = await ensureChannel();
|
|
5464
|
+
try {
|
|
5465
|
+
const response = await withWorkspaceControl(
|
|
5466
|
+
info,
|
|
5467
|
+
() => withTimeout(
|
|
5468
|
+
Promise.race([
|
|
5469
|
+
info.connection.extMethod(
|
|
5470
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryDream,
|
|
5471
|
+
{ cwd: boundWorkspace }
|
|
5472
|
+
),
|
|
5473
|
+
getChannelClosedReject(info)
|
|
5474
|
+
]),
|
|
5475
|
+
WORKSPACE_MEMORY_REMEMBER_TIMEOUT_MS,
|
|
5476
|
+
SERVE_CONTROL_EXT_METHODS.workspaceMemoryDream
|
|
5477
|
+
)
|
|
5478
|
+
);
|
|
5479
|
+
return parseWorkspaceMemoryDreamResult(response);
|
|
5480
|
+
} finally {
|
|
5481
|
+
if (hasNoChannelWork(info)) {
|
|
5482
|
+
await startIdleTimer(info, "workspace memory dream");
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
},
|
|
4145
5486
|
async getWorkspaceMcpToolsStatus(serverName) {
|
|
4146
5487
|
return requestWorkspaceStatus(
|
|
4147
5488
|
SERVE_STATUS_EXT_METHODS.workspaceMcpTools,
|
|
@@ -5214,6 +6555,7 @@ __name(withTimeout, "withTimeout");
|
|
|
5214
6555
|
var createHttpAcpBridge = createAcpSessionBridge;
|
|
5215
6556
|
|
|
5216
6557
|
export {
|
|
6558
|
+
SessionArtifactValidationError,
|
|
5217
6559
|
extractErrorMessage,
|
|
5218
6560
|
extractErrorCode,
|
|
5219
6561
|
createAcpSessionBridge,
|
|
@@ -5224,3 +6566,8 @@ export {
|
|
|
5224
6566
|
* Copyright 2025 Qwen Team
|
|
5225
6567
|
* SPDX-License-Identifier: Apache-2.0
|
|
5226
6568
|
*/
|
|
6569
|
+
/**
|
|
6570
|
+
* @license
|
|
6571
|
+
* Copyright 2026 Qwen Team
|
|
6572
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
6573
|
+
*/
|