@qwen-code/qwen-code 0.19.5 → 0.19.6-nightly.20260704.5dc2e1501

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.
Files changed (235) hide show
  1. package/bundled/dataviz/SKILL.md +50 -0
  2. package/bundled/dataviz/references/anti-patterns.md +12 -0
  3. package/bundled/dataviz/references/choosing-a-form.md +16 -0
  4. package/bundled/dataviz/references/palette.md +57 -0
  5. package/bundled/dataviz/scripts/validate_palette.js +328 -0
  6. package/bundled/loop/SKILL.md +1 -1
  7. package/bundled/qc-helper/docs/configuration/settings.md +9 -8
  8. package/bundled/qc-helper/docs/features/headless.md +2 -2
  9. package/bundled/qc-helper/docs/features/scheduled-tasks.md +4 -2
  10. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
  11. package/bundled/review/DESIGN.md +23 -0
  12. package/bundled/review/SKILL.md +65 -8
  13. package/chunks/{MaxSizedBox-5JV77KRA.js → MaxSizedBox-44K34KSF.js} +14 -14
  14. package/chunks/{StandaloneSessionPicker-MGUGB6PH.js → StandaloneSessionPicker-6WZYYTZE.js} +25 -25
  15. package/chunks/{acpAgent-4F36XM3X.js → acpAgent-2CMYPFHV.js} +346 -131
  16. package/chunks/{agent-IWBUZI6A.js → agent-UOEAYBCX.js} +11 -11
  17. package/chunks/{agent-headless-JUTICAYO.js → agent-headless-7SCVZZGJ.js} +11 -11
  18. package/chunks/{anthropicContentGenerator-WL3LJOUB.js → anthropicContentGenerator-H5ZOEENQ.js} +2 -2
  19. package/chunks/{artifact-tool-W76WC2JX.js → artifact-tool-SLYPWG3C.js} +15 -2
  20. package/chunks/{askUserQuestion-J3P6TH3V.js → askUserQuestion-OKPTECON.js} +1 -1
  21. package/chunks/{bridge-DHZHQ4UV.js → bridge-IGX2XPWV.js} +17 -16
  22. package/chunks/{channel-worker-supervisor-EVPAYNZ5.js → channel-worker-supervisor-JUYQ5Z4R.js} +5 -5
  23. package/chunks/{chunk-EROWZQN7.js → chunk-2HK52TS2.js} +6 -6
  24. package/chunks/chunk-3RW4AZJV.js +5063 -0
  25. package/chunks/chunk-3VJ7MT3N.js +111 -0
  26. package/chunks/{chunk-JJ6B3ZD3.js → chunk-3ZSJDRNO.js} +2 -2
  27. package/chunks/{chunk-SJVPSHXU.js → chunk-4OIKNWUQ.js} +4 -4
  28. package/chunks/{chunk-PPFWEV7G.js → chunk-4RQIB5UZ.js} +62 -62
  29. package/chunks/{chunk-MDBNFHIO.js → chunk-4YMVQKCZ.js} +3 -3
  30. package/chunks/{chunk-2YH27UNF.js → chunk-4YXBDLX7.js} +1 -1
  31. package/chunks/{chunk-6QVQZAW6.js → chunk-537ZUZEH.js} +1 -1
  32. package/chunks/{chunk-L7OJ3ZO3.js → chunk-5ES5YPED.js} +1 -1
  33. package/chunks/{chunk-UJT42DB6.js → chunk-5QC7Y5TJ.js} +5 -5
  34. package/chunks/{chunk-BC4R5C5R.js → chunk-5WYLPENX.js} +32 -6
  35. package/chunks/{chunk-7DMQRPC7.js → chunk-6BEOH4KK.js} +1 -1
  36. package/chunks/{chunk-CXBG27SF.js → chunk-6IAWPIQ6.js} +3 -2
  37. package/chunks/{chunk-RM3PGSGL.js → chunk-6SHO7WFF.js} +15 -2
  38. package/chunks/{chunk-CBJE2PLG.js → chunk-777PHAJF.js} +2 -2
  39. package/chunks/{chunk-NSSVORTQ.js → chunk-7UU2AGR4.js} +16 -12
  40. package/chunks/{chunk-RNGAT2Y2.js → chunk-AGLMKJH5.js} +1 -1
  41. package/chunks/{chunk-J3ERRYYI.js → chunk-AWSTZHHZ.js} +2 -2
  42. package/chunks/{chunk-6QTCOQX7.js → chunk-B5ZACOMA.js} +1967 -1399
  43. package/chunks/{chunk-R6RI2HIC.js → chunk-CLQPBI4H.js} +40 -13
  44. package/chunks/{chunk-SJBIFVD2.js → chunk-DMSNJDWG.js} +5 -1
  45. package/chunks/{chunk-KKQWC6WS.js → chunk-DNV4FSN5.js} +1 -1
  46. package/chunks/{chunk-Z7XNVNPM.js → chunk-EMSRFDBD.js} +1 -1
  47. package/chunks/{chunk-HISPEX42.js → chunk-G645A66S.js} +7 -7
  48. package/chunks/{chunk-WALEWZ44.js → chunk-H3GBYW5M.js} +1 -1
  49. package/chunks/{chunk-2Z43HUXT.js → chunk-HLKG6CZN.js} +3 -2
  50. package/chunks/{chunk-XKZXGIRM.js → chunk-HNGXPBWR.js} +2 -2
  51. package/chunks/{chunk-QHYITL6P.js → chunk-HXX7S2AE.js} +5 -11
  52. package/chunks/{chunk-XKSCTXPK.js → chunk-J6ABRKAB.js} +2 -1
  53. package/chunks/{chunk-DX3TKXNT.js → chunk-JA5KWZTJ.js} +1 -1
  54. package/chunks/{chunk-4MCC4XHH.js → chunk-KBKWNEPS.js} +38 -37
  55. package/chunks/{chunk-MNOXKSM2.js → chunk-KEKV2TOO.js} +1 -1
  56. package/chunks/{chunk-R3UWLLRQ.js → chunk-KP6O77UN.js} +1 -1
  57. package/chunks/{chunk-YTFBURQD.js → chunk-KYTQOCDE.js} +1 -1
  58. package/chunks/{chunk-TN6RT6EJ.js → chunk-LJUWNRJH.js} +16 -4
  59. package/chunks/{chunk-BPFJQGY7.js → chunk-LM3YCCZJ.js} +164 -5
  60. package/chunks/{chunk-G4M7FPNY.js → chunk-M6IUEDXM.js} +1 -1
  61. package/chunks/{chunk-MTNTVOJR.js → chunk-MJKMIQMK.js} +5 -2
  62. package/chunks/{chunk-2CAII5HD.js → chunk-MWGIMAYM.js} +1 -1
  63. package/chunks/{chunk-NDY7OENU.js → chunk-N3QDCSLP.js} +2 -2
  64. package/chunks/{chunk-IMAMNLY6.js → chunk-N6AGVKMC.js} +3 -3
  65. package/chunks/{chunk-WZ724G6K.js → chunk-NGCPNXJC.js} +5 -5
  66. package/chunks/{chunk-YXK4GPYO.js → chunk-NVFJSIAX.js} +29 -0
  67. package/chunks/{chunk-6KPZJJ6U.js → chunk-P2OIJOKP.js} +9 -9
  68. package/chunks/{chunk-RSBQS6M4.js → chunk-P2RRV2UB.js} +1 -1
  69. package/chunks/{chunk-NNEJEBCF.js → chunk-PGMCFUZS.js} +30 -21
  70. package/chunks/{chunk-CSPSJU5R.js → chunk-PNGENHT7.js} +16 -16
  71. package/chunks/{chunk-Y4UQT3PM.js → chunk-QQXG2BL6.js} +1 -1
  72. package/chunks/{chunk-M5ITDKSM.js → chunk-RUM2UEL3.js} +1 -1
  73. package/chunks/{chunk-DG573EOO.js → chunk-RZORUN6X.js} +1 -1
  74. package/chunks/{chunk-LHMZCIKL.js → chunk-SZFYG244.js} +3 -1
  75. package/chunks/{chunk-CHY5C5T4.js → chunk-TDMIHT6B.js} +171 -79
  76. package/chunks/{chunk-DRS2HTNT.js → chunk-TE6JTKY5.js} +5 -5
  77. package/chunks/chunk-U7UXWKGG.js +949 -0
  78. package/chunks/{chunk-JKGCBO3O.js → chunk-UPYORLKQ.js} +3 -3
  79. package/chunks/{chunk-UY2TCIZS.js → chunk-V5VTULL5.js} +2 -2
  80. package/chunks/{chunk-ZISMVA6U.js → chunk-WGCLCXAN.js} +1371 -24
  81. package/chunks/chunk-WSOGYJMT.js +5630 -0
  82. package/chunks/{chunk-SBMHB6N5.js → chunk-WWGZJJRG.js} +12 -12
  83. package/chunks/{chunk-DM4E337C.js → chunk-X3UQVEBR.js} +4 -4
  84. package/chunks/{chunk-K4I4STSL.js → chunk-XPOO5OMB.js} +2 -2
  85. package/chunks/{chunk-5B2WNM6V.js → chunk-ZI4MGBB5.js} +1 -1
  86. package/chunks/{chunk-OQHLUA2Y.js → chunk-ZLJKZ57K.js} +3 -3
  87. package/chunks/{chunk-YCU7QV7Q.js → chunk-ZZDAIAA6.js} +32 -0
  88. package/chunks/{computer-use-ON3JQUHW.js → computer-use-TQWGUBPQ.js} +11 -11
  89. package/chunks/{contextCommand-OGCG7W6N.js → contextCommand-XDK5RNWI.js} +13 -13
  90. package/chunks/{cron-create-6YTCOX6P.js → cron-create-7JYUDTUY.js} +20 -5
  91. package/chunks/{cron-delete-E3NIFSUK.js → cron-delete-YPULQQAK.js} +2 -2
  92. package/chunks/{cron-list-Q64MNQNE.js → cron-list-HJIW5MHP.js} +2 -2
  93. package/chunks/{daemon-EEB2RYOL.js → daemon-7XYW4BC3.js} +102 -0
  94. package/chunks/{daemon-status-provider-P72STMLB.js → daemon-status-provider-6UEN56WN.js} +20 -19
  95. package/chunks/{dist-AP5V4WYU.js → dist-AAO65DPC.js} +2 -2
  96. package/chunks/{dist-X4ZDE726.js → dist-ABQ7VWRR.js} +3 -3
  97. package/chunks/{dist-SNXOUPYS.js → dist-AW5ZYMUI.js} +2 -2
  98. package/chunks/{dist-Z57Q4YF5.js → dist-BV56HW3W.js} +276 -95
  99. package/chunks/{dist-IZP2VV4C.js → dist-JPSVN367.js} +2 -2
  100. package/chunks/{earlyInputCapture-DAFHSGVW.js → earlyInputCapture-7MNFMUJE.js} +11 -11
  101. package/chunks/{edit-3QFNCSZH.js → edit-HOC63PHG.js} +12 -12
  102. package/chunks/{en-M4EBUBNU.js → en-XR3S5VWY.js} +1 -0
  103. package/chunks/{enter-worktree-62EQQMLD.js → enter-worktree-THXLMUX2.js} +11 -11
  104. package/chunks/{enterPlanMode-VUQSE4EG.js → enterPlanMode-TW4WQVEI.js} +11 -11
  105. package/chunks/{errors-PW75PZXE.js → errors-NTNVSC6G.js} +13 -13
  106. package/chunks/{exit-worktree-VVNH7OVY.js → exit-worktree-CLL7RGAT.js} +11 -11
  107. package/chunks/{exitPlanMode-RUYRCYZW.js → exitPlanMode-BTZZ3QEL.js} +11 -11
  108. package/chunks/{fast-path-TFRJRTTR.js → fast-path-RYXBU6AS.js} +3 -3
  109. package/chunks/{fast-path-settings-UQLRFDQP.js → fast-path-settings-RCRXH2JG.js} +2 -2
  110. package/chunks/{gemini-XW7ZDUVR.js → gemini-36FE3OHS.js} +69 -64
  111. package/chunks/{geminiContentGenerator-MZDVHVZH.js → geminiContentGenerator-JEG2PANG.js} +1 -1
  112. package/chunks/{glob-WAY2PUWA.js → glob-EYVHOFCY.js} +11 -11
  113. package/chunks/{grep-W6CBKSYC.js → grep-TZY5TDGH.js} +11 -11
  114. package/chunks/{initializer-HK2XE6P2.js → initializer-HPF2RBSB.js} +16 -16
  115. package/chunks/{list-RVLIIKKL.js → list-THUTQ7B5.js} +18 -18
  116. package/chunks/{loadedSettingsAdapter-C63OUYZC.js → loadedSettingsAdapter-CUMWJNWJ.js} +16 -16
  117. package/chunks/{loop-wakeup-G2EHBRGR.js → loop-wakeup-34YK7T7O.js} +3 -3
  118. package/chunks/{ls-IDHUVSAG.js → ls-MPD5OJUX.js} +1 -1
  119. package/chunks/{lsp-FSRYXGFT.js → lsp-72PWTDW7.js} +1 -1
  120. package/chunks/{workspace-skills-status-ONEPXJV6.js → mcp-NQD5MT2T.js} +20 -16
  121. package/chunks/{monitor-FOG36ABM.js → monitor-PB7NVSG2.js} +11 -11
  122. package/chunks/{nonInteractiveCli-6BYQSJTB.js → nonInteractiveCli-F5FJXYQR.js} +46 -44
  123. package/chunks/{notebook-edit-GC6NXRCX.js → notebook-edit-LAK6OHS6.js} +12 -12
  124. package/chunks/{openaiContentGenerator-EXR3ZL3Z.js → openaiContentGenerator-GMMEY5PG.js} +6 -6
  125. package/chunks/{pidfile-FNZM2DDH.js → pidfile-NQ2YUNKI.js} +11 -11
  126. package/chunks/{qwenContentGenerator-A7B6J4U7.js → qwenContentGenerator-7XCBMQBM.js} +13 -13
  127. package/chunks/{read-file-6JL4ULMY.js → read-file-KUROJDUQ.js} +3 -3
  128. package/chunks/{read-mcp-resource-PIJF24RO.js → read-mcp-resource-OWOBJY72.js} +1 -1
  129. package/chunks/record-artifact-URK3YUDJ.js +343 -0
  130. package/chunks/{ripGrep-DIUGLJE5.js → ripGrep-USDWBX4L.js} +11 -11
  131. package/chunks/{run-qwen-serve-CME3AKM4.js → run-qwen-serve-WKCKS23N.js} +72 -28
  132. package/chunks/{scheduler-L7F6GDDT.js → scheduler-QR4F5TAH.js} +11 -11
  133. package/chunks/{send-message-33PYFMCT.js → send-message-L7OLQEKH.js} +2 -2
  134. package/chunks/{serve-SRCBOJGP.js → serve-2EIPX62G.js} +18 -18
  135. package/chunks/{server-QSQ45QFR.js → server-UJ7ZF5D7.js} +1184 -490
  136. package/chunks/{session-5DG6NXHZ.js → session-XB3CFJ6R.js} +48 -46
  137. package/chunks/{settings-3EEQI4MN.js → settings-DYVJFW5H.js} +15 -15
  138. package/chunks/{shell-B7FNYF5S.js → shell-IG7KGPLR.js} +11 -11
  139. package/chunks/{skill-AAOGHD5O.js → skill-RWX646DC.js} +4 -4
  140. package/chunks/{spawnChannel-3CBN3ZLK.js → spawnChannel-GWIJHDZ5.js} +15 -15
  141. package/chunks/{src-T5A7P7FS.js → src-IYODJOVK.js} +47 -21
  142. package/chunks/{startInteractiveUI-2FGEQ6AS.js → startInteractiveUI-PLEZAI44.js} +354 -152
  143. package/chunks/{syntheticOutput-YOSWIHDJ.js → syntheticOutput-J3MLCQAR.js} +2 -2
  144. package/chunks/{task-create-NHS2NGB3.js → task-create-ELEBZ7H2.js} +3 -3
  145. package/chunks/{task-list-5UIB564R.js → task-list-IEUZLF3Y.js} +1 -1
  146. package/chunks/{task-stop-HGXZ2VZ3.js → task-stop-QEZW3UDY.js} +1 -1
  147. package/chunks/{task-update-IYYWUILG.js → task-update-DW36J5P5.js} +3 -3
  148. package/chunks/{team-create-KDF6W6PV.js → team-create-RXRE7FCH.js} +11 -11
  149. package/chunks/{team-delete-FEKJCU4P.js → team-delete-SVITIMBO.js} +1 -1
  150. package/chunks/{team-plan-approval-PSFKQX7M.js → team-plan-approval-OJDMQXOK.js} +11 -11
  151. package/chunks/{theme-manager-5XOA2AO7.js → theme-manager-QBK6PZOQ.js} +11 -11
  152. package/chunks/{todoWrite-TKMVZ2HT.js → todoWrite-SFFQHZYY.js} +2 -2
  153. package/chunks/{tool-search-LFRILZXC.js → tool-search-EZQYPVFF.js} +4 -4
  154. package/chunks/{trustedFolders-7HQY6T6X.js → trustedFolders-GZDMSATB.js} +12 -12
  155. package/chunks/{validateNonInterActiveAuth-UC27B7BA.js → validateNonInterActiveAuth-AHXCFAV6.js} +43 -41
  156. package/chunks/version-KQ5CA4C5.js +10 -0
  157. package/chunks/{web-fetch-J4PIW36Q.js → web-fetch-SXAXJHIO.js} +2 -2
  158. package/chunks/{workflow-KUTESS6L.js → workflow-KUBRBYWH.js} +20 -13
  159. package/chunks/{workspace-providers-status-LJT5AQDS.js → workspace-providers-status-LRMZ4KYI.js} +18 -18
  160. package/chunks/{workspace-service-YOBYVDXH.js → workspace-service-5UYFHP42.js} +23 -23
  161. package/chunks/workspace-skills-status-TKLU5O2X.js +68 -0
  162. package/chunks/{write-file-FJYBZUHP.js → write-file-37LNLFQC.js} +12 -12
  163. package/chunks/yargs-B64EYTCF.js +10 -0
  164. package/chunks/{zh-SLZNSSZB.js → zh-FSVJTXA4.js} +1 -0
  165. package/chunks/{zh-TW-P53C2SL5.js → zh-TW-66MG4LWL.js} +1 -0
  166. package/cli-entry.js +81 -8
  167. package/cli.js +348 -55
  168. package/locales/en.js +1 -0
  169. package/locales/zh-TW.js +1 -0
  170. package/locales/zh.js +1 -0
  171. package/node_modules/@qwen-code/audio-capture/package.json +1 -1
  172. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
  173. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
  174. package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
  175. package/package.json +3 -3
  176. package/web-shell/assets/{arc-D_rAuMDd.js → arc-CUpe0ibu.js} +1 -1
  177. package/web-shell/assets/{architectureDiagram-3BPJPVTR-DUCzbHVo.js → architectureDiagram-3BPJPVTR-JvyrY_mK.js} +1 -1
  178. package/web-shell/assets/{blockDiagram-GPEHLZMM-BEEBt1LL.js → blockDiagram-GPEHLZMM-CK3Y_vom.js} +1 -1
  179. package/web-shell/assets/{c4Diagram-AAUBKEIU-5ZJ_DeFL.js → c4Diagram-AAUBKEIU-DprSnyrf.js} +1 -1
  180. package/web-shell/assets/channel-BAxQ2-aZ.js +1 -0
  181. package/web-shell/assets/{chunk-2J33WTMH-Cfw7EiLn.js → chunk-2J33WTMH-DJtRJPmu.js} +1 -1
  182. package/web-shell/assets/{chunk-4BX2VUAB-FGuZNCZY.js → chunk-4BX2VUAB-ON6Q2-BG.js} +1 -1
  183. package/web-shell/assets/{chunk-55IACEB6-CaBwYPBF.js → chunk-55IACEB6-c60ou5HZ.js} +1 -1
  184. package/web-shell/assets/{chunk-727SXJPM-BlR04OFz.js → chunk-727SXJPM-BamtPKxx.js} +1 -1
  185. package/web-shell/assets/{chunk-AQP2D5EJ-D3_mYJH5.js → chunk-AQP2D5EJ-CsVgpu-T.js} +1 -1
  186. package/web-shell/assets/{chunk-FMBD7UC4-7D4q4SbB.js → chunk-FMBD7UC4-vZrpjAx4.js} +1 -1
  187. package/web-shell/assets/{chunk-ND2GUHAM-BjX_Iwmr.js → chunk-ND2GUHAM-qxyNOd5t.js} +1 -1
  188. package/web-shell/assets/{chunk-QZHKN3VN-C3Hz_ZQh.js → chunk-QZHKN3VN-BvTJSM_S.js} +1 -1
  189. package/web-shell/assets/classDiagram-4FO5ZUOK-Cvd_xhZI.js +1 -0
  190. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Cvd_xhZI.js +1 -0
  191. package/web-shell/assets/{cose-bilkent-S5V4N54A-Ax4UycaT.js → cose-bilkent-S5V4N54A-1tXB4pju.js} +1 -1
  192. package/web-shell/assets/{dagre-BM42HDAG-C6hmPtGt.js → dagre-BM42HDAG-DglBzme8.js} +1 -1
  193. package/web-shell/assets/{diagram-2AECGRRQ-tXZnxjmw.js → diagram-2AECGRRQ-DEJpqsWz.js} +1 -1
  194. package/web-shell/assets/{diagram-5GNKFQAL-99dwIzQG.js → diagram-5GNKFQAL-CsQ1NrMG.js} +1 -1
  195. package/web-shell/assets/{diagram-KO2AKTUF-Bqhn0-2s.js → diagram-KO2AKTUF-Z-3codAi.js} +1 -1
  196. package/web-shell/assets/{diagram-LMA3HP47-DzThVSvo.js → diagram-LMA3HP47-mBuPTA2i.js} +1 -1
  197. package/web-shell/assets/{diagram-OG6HWLK6-DPE8vjln.js → diagram-OG6HWLK6-tcA3K3s9.js} +1 -1
  198. package/web-shell/assets/{erDiagram-TEJ5UH35-KzUKgQCV.js → erDiagram-TEJ5UH35-D9bXFRyZ.js} +1 -1
  199. package/web-shell/assets/{flowDiagram-I6XJVG4X-DBN-DXw5.js → flowDiagram-I6XJVG4X-Ck0Py04s.js} +1 -1
  200. package/web-shell/assets/{ganttDiagram-6RSMTGT7-DuBsP9u8.js → ganttDiagram-6RSMTGT7-rOevCekE.js} +1 -1
  201. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BjWHMyKR.js → gitGraphDiagram-PVQCEYII-CoPQaLj0.js} +1 -1
  202. package/web-shell/assets/index-Cr7MYW6T.css +5 -0
  203. package/web-shell/assets/index-DCHPAUp3.js +730 -0
  204. package/web-shell/assets/{infoDiagram-5YYISTIA-BVux0vP6.js → infoDiagram-5YYISTIA-a77CUKoI.js} +1 -1
  205. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-2qzw7f--.js → ishikawaDiagram-YF4QCWOH-DlLgUAO-.js} +1 -1
  206. package/web-shell/assets/{journeyDiagram-JHISSGLW-Dnl65sxL.js → journeyDiagram-JHISSGLW-BXR5kVAZ.js} +1 -1
  207. package/web-shell/assets/{kanban-definition-UN3LZRKU-BElSQYtY.js → kanban-definition-UN3LZRKU-h5CoHZg7.js} +1 -1
  208. package/web-shell/assets/{linear-BjoycSSY.js → linear-BkaREbyD.js} +1 -1
  209. package/web-shell/assets/{mermaid.core-xe6bvMRz.js → mermaid.core-Bkagz0ng.js} +5 -5
  210. package/web-shell/assets/{mindmap-definition-RKZ34NQL-D8DQgI4U.js → mindmap-definition-RKZ34NQL-D7EMKR_5.js} +1 -1
  211. package/web-shell/assets/{pieDiagram-4H26LBE5-Dwh7Gp7c.js → pieDiagram-4H26LBE5-DAmPOjsL.js} +1 -1
  212. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BXKNBln2.js → quadrantDiagram-W4KKPZXB-e4WFQkQu.js} +1 -1
  213. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BzaC3cIA.js → requirementDiagram-4Y6WPE33-v1zo7OiV.js} +1 -1
  214. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-DP2t7eZk.js → sankeyDiagram-5OEKKPKP-Bstm4aW_.js} +1 -1
  215. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-XlFiWEYv.js → sequenceDiagram-3UESZ5HK-DzcZy6xN.js} +1 -1
  216. package/web-shell/assets/{stateDiagram-AJRCARHV-CupgUMJO.js → stateDiagram-AJRCARHV-BEJH6YbH.js} +1 -1
  217. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BopifCBI.js +1 -0
  218. package/web-shell/assets/{timeline-definition-PNZ67QCA-DstuGywa.js → timeline-definition-PNZ67QCA-TI1wH-Pm.js} +1 -1
  219. package/web-shell/assets/{vennDiagram-CIIHVFJN-CnbNp6zu.js → vennDiagram-CIIHVFJN-YaH8VDMS.js} +1 -1
  220. package/web-shell/assets/{wardley-L42UT6IY-DnvoHq6R.js → wardley-L42UT6IY-B80co7OP.js} +1 -1
  221. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-Cz0xHEWB.js → wardleyDiagram-YWT4CUSO-4fHNDEMl.js} +1 -1
  222. package/web-shell/assets/{xychartDiagram-2RQKCTM6-p36gfo88.js → xychartDiagram-2RQKCTM6-DT3q4Z3J.js} +1 -1
  223. package/web-shell/index.html +2 -2
  224. package/bundled/loop/SKILL.test.ts +0 -119
  225. package/bundled/loop/autonomous-loop.test.ts +0 -59
  226. package/bundled/loop/loop-task-file.test.ts +0 -1064
  227. package/bundled/loop/loop-tick-resolver.test.ts +0 -906
  228. package/chunks/chunk-EJ7BN3EN.js +0 -11396
  229. package/web-shell/assets/channel-B5ynH0q8.js +0 -1
  230. package/web-shell/assets/classDiagram-4FO5ZUOK-CK3ibywp.js +0 -1
  231. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CK3ibywp.js +0 -1
  232. package/web-shell/assets/index-9qfvU0_r.css +0 -5
  233. package/web-shell/assets/index-CWzDaQT5.js +0 -717
  234. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-By3E4QwN.js +0 -1
  235. 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-EROWZQN7.js";
44
+ } from "./chunk-2HK52TS2.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-LHMZCIKL.js";
49
- import {
50
- ClientSideConnection,
51
- PROTOCOL_VERSION,
52
- RequestError
53
- } from "./chunk-UFC57OYT.js";
53
+ } from "./chunk-SZFYG244.js";
54
54
  import {
55
55
  ShellExecutionService,
56
56
  TrustGateError
57
- } from "./chunk-6QTCOQX7.js";
57
+ } from "./chunk-B5ZACOMA.js";
58
58
  import {
59
59
  DAEMON_TRACEPARENT_META_KEY,
60
60
  DAEMON_TRACESTATE_META_KEY
61
- } from "./chunk-CHY5C5T4.js";
61
+ } from "./chunk-TDMIHT6B.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 path2 from "node:path";
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 oldest = this.resolvedOrder.shift();
947
- if (oldest !== void 0) this.resolved.delete(oldest);
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: params,
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. Six methods are
1339
- * recognized — `qwen/notify/session/model-update`,
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 hasControlCharacter(value) {
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(hasControlCharacter, "hasControlCharacter");
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 (!path2.isAbsolute(opts.boundWorkspace)) {
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: /* @__PURE__ */ new Set(),
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 (!path2.isAbsolute(workspaceCwd)) {
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 (hasControlCharacter(metadata.displayName)) {
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 (!path2.isAbsolute(workspaceCwd)) return [];
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
+ */