@cardstack/boxel-cli 0.3.2-unstable.61 → 0.4.0-unstable.0

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 (312) hide show
  1. package/bundled-test-harness/assets/adapter-unm-Xq4g.js +2 -0
  2. package/bundled-test-harness/assets/{add-field-to-card-definition-command-test-DkxmkPH6.js → add-field-to-card-definition-command-test-CCaDu5uP.js} +2 -2
  3. package/bundled-test-harness/assets/{add-workspace-test-BMKxSlaC.js → add-workspace-test-B_ih3mkL.js} +2 -2
  4. package/bundled-test-harness/assets/{ai-assistant-test-C3LjW9Uz.js → ai-assistant-test-CrQxlWpZ.js} +7 -6
  5. package/bundled-test-harness/assets/{ai-function-generation-test-WqD9vlzP.js → ai-function-generation-test-BkTvuCnq.js} +1 -1
  6. package/bundled-test-harness/assets/{ai-module-creation-test-CeP1V90-.js → ai-module-creation-test-CMLVMpYm.js} +3 -3
  7. package/bundled-test-harness/assets/{app-C8fZHSIY.js → app-BQLXfOdp.js} +309 -21
  8. package/bundled-test-harness/assets/{apply-markdown-edit-test-VkN9mVg4.js → apply-markdown-edit-test-CpeCS12T.js} +2 -2
  9. package/bundled-test-harness/assets/{apply-search-replace-block-test-C4GiLUbz.js → apply-search-replace-block-test-Czoi47xr.js} +1 -1
  10. package/bundled-test-harness/assets/{auth-service-worker-registration-CGUqW_lr.js → auth-service-worker-registration-C3rAs9Yi.js} +1 -1
  11. package/bundled-test-harness/assets/{auth-service-worker-test-DjVH_n4v.js → auth-service-worker-test-DTHQyoUg.js} +3 -3
  12. package/bundled-test-harness/assets/{authed-fetch-test-PT9AWQEk.js → authed-fetch-test-BRqybmXe.js} +2 -2
  13. package/bundled-test-harness/assets/{avif-image-def-test-BMFnvMFY.js → avif-image-def-test-BVwv4Ahc.js} +1 -1
  14. package/bundled-test-harness/assets/{basic-test-B5EcLZRP.js → basic-test-Dbky79J2.js} +1 -1
  15. package/bundled-test-harness/assets/{binary-upload-dedupe-test-BvQVNF95.js → binary-upload-dedupe-test-B7dPaGQN.js} +3 -3
  16. package/bundled-test-harness/assets/{bot-registration-test-Cy1HY7PT.js → bot-registration-test-zrufhFTo.js} +2 -2
  17. package/bundled-test-harness/assets/{box-test-BTOPLQ3k.js → box-test-B85wfMJn.js} +1 -1
  18. package/bundled-test-harness/assets/{brand-guide-attachments-test-C4R_z8N5.js → brand-guide-attachments-test-C8-n-naq.js} +2 -2
  19. package/bundled-test-harness/assets/{brand-guide-custom-css-test-Me-k86li.js → brand-guide-custom-css-test-B2fmvFp4.js} +2 -2
  20. package/bundled-test-harness/assets/{brand-logo-mark-field-test-DcCSpYJq.js → brand-logo-mark-field-test-CJ4s6jjd.js} +2 -2
  21. package/bundled-test-harness/assets/{broken-link-template-test-BRD2BX45.js → broken-link-template-test-BAc48VK4.js} +1 -1
  22. package/bundled-test-harness/assets/{can-read-realm-test-_flXUfS4.js → can-read-realm-test-mHnz9-_s.js} +2 -2
  23. package/bundled-test-harness/assets/{cancel-indexing-job-test-0JyPszPo.js → cancel-indexing-job-test-Drx2ghoA.js} +2 -2
  24. package/bundled-test-harness/assets/{card-api-test-BpeMpeQ0.js → card-api-test-BmiwtCFR.js} +2 -2
  25. package/bundled-test-harness/assets/{card-basics-test-C-UCeun-.js → card-basics-test-DZs6Zh6Z.js} +2 -2
  26. package/bundled-test-harness/assets/{card-catalog-test-4K3_LE47.js → card-catalog-test-D2mEHOpL.js} +3 -3
  27. package/bundled-test-harness/assets/{card-copy-test-BFFsV3G-.js → card-copy-test-DpSavuvN.js} +3 -3
  28. package/bundled-test-harness/assets/{card-def-field-def-relationships-test-CRjFV5pq.js → card-def-field-def-relationships-test-DYX_ubhX.js} +3 -3
  29. package/bundled-test-harness/assets/{card-def-menu-items-test-DQNnU_0P.js → card-def-menu-items-test-DLO6TEhC.js} +1 -1
  30. package/bundled-test-harness/assets/{card-delete-test-DOyt5y-x.js → card-delete-test-Bmp8Ue48.js} +3 -3
  31. package/bundled-test-harness/assets/{card-playground-test-CiESzD5-.js → card-playground-test-DxoIBbjx.js} +3 -3
  32. package/bundled-test-harness/assets/{card-search-adorn-test-DdTUl5RY.js → card-search-adorn-test-CEA5iAcD.js} +1 -1
  33. package/bundled-test-harness/assets/{card-search-selection-menu-test-BJFUbgA1.js → card-search-selection-menu-test-DOLM6HU0.js} +1 -1
  34. package/bundled-test-harness/assets/{check-correctness-test-B4E7WXSZ.js → check-correctness-test-DR1rUhtU.js} +1 -1
  35. package/bundled-test-harness/assets/{check-domain-availability-test-BnmsW2P7.js → check-domain-availability-test-BYAkVLGj.js} +2 -2
  36. package/bundled-test-harness/assets/{code-patches-test-6Lvfhm1l.js → code-patches-test-BDg35i4X.js} +1 -1
  37. package/bundled-test-harness/assets/{code-ref-test-BWuTdZ2e.js → code-ref-test-BZGL3teK.js} +1 -1
  38. package/bundled-test-harness/assets/{code-submode-test-DPzE9tKe.js → code-submode-test-DIiXgCRB.js} +3 -3
  39. package/bundled-test-harness/assets/{codeblocks-test-MV1tHflj.js → codeblocks-test-B-i0v3er.js} +3 -3
  40. package/bundled-test-harness/assets/{codemirror-editor-test-SD3gDmHw.js → codemirror-editor-test-e1Yn_b_1.js} +1 -1
  41. package/bundled-test-harness/assets/{color-field-test-C_7cf4Z2.js → color-field-test-okcvtdsF.js} +2 -2
  42. package/bundled-test-harness/assets/{commands-calling-test-Br4sMoMf.js → commands-calling-test-BETL8EWm.js} +2 -2
  43. package/bundled-test-harness/assets/{commands-test-COT9Ck-6.js → commands-test-C13_nhjT.js} +1 -1
  44. package/bundled-test-harness/assets/{commands-test-71b4Fun5.js → commands-test-D1X-Kikc.js} +3 -3
  45. package/bundled-test-harness/assets/{computed-test-BbCVTMkD.js → computed-test-C2j8r-e_.js} +2 -2
  46. package/bundled-test-harness/assets/{container-BVdtw4NT.js → container-DYJ5z0jP.js} +3 -3
  47. package/bundled-test-harness/assets/{copy-and-edit-test-1xrTe8p1.js → copy-and-edit-test-DqV_dpu_.js} +1 -1
  48. package/bundled-test-harness/assets/{copy-card-test-D0rXx03h.js → copy-card-test-B4dNP03f.js} +1 -1
  49. package/bundled-test-harness/assets/{copy-file-to-realm-test-DxW5PABL.js → copy-file-to-realm-test-oGK9EM0P.js} +1 -1
  50. package/bundled-test-harness/assets/{copy-source-test-Dy83btnV.js → copy-source-test-GtNFw5fv.js} +2 -2
  51. package/bundled-test-harness/assets/{create-file-test-DimDxpRl.js → create-file-test-2WPpTJ5F.js} +1 -1
  52. package/bundled-test-harness/assets/{create-file-test-COppMhde.js → create-file-test-HxkEMHWL.js} +2 -2
  53. package/bundled-test-harness/assets/{create-listing-modal-test-D57Altg2.js → create-listing-modal-test-BIG3NbX-.js} +4 -4
  54. package/bundled-test-harness/assets/{create-listing-pr-request-test-HJmFkx_x.js → create-listing-pr-request-test-2ZRF_IBk.js} +2 -2
  55. package/bundled-test-harness/assets/{create-spec-test-C-4bkoj3.js → create-spec-test-JVOisAUl.js} +1 -1
  56. package/bundled-test-harness/assets/{csv-file-def-test-GOmD6Ikx.js → csv-file-def-test-DIVp_7a6.js} +1 -1
  57. package/bundled-test-harness/assets/{date-time-fields-test-BYn57092.js → date-time-fields-test-BWdrrYdj.js} +2 -2
  58. package/bundled-test-harness/assets/{debug-message-test-CNzx_IFI.js → debug-message-test-CAzyW7l3.js} +3 -3
  59. package/bundled-test-harness/assets/{diffing-test-PA40XPFB.js → diffing-test-JzXF051K.js} +1 -1
  60. package/bundled-test-harness/assets/{editor-test-Dg1fTno0.js → editor-test-j9znzFxy.js} +2 -2
  61. package/bundled-test-harness/assets/{email-field-test-rPWkRvgR.js → email-field-test-D4vZ2Qnc.js} +2 -2
  62. package/bundled-test-harness/assets/{enum-field-test-DjQ-sjAR.js → enum-field-test-DtZ_sOiA.js} +2 -2
  63. package/bundled-test-harness/assets/{error-display-test-Cp1vgWSg.js → error-display-test-Btk0RcqS.js} +1 -1
  64. package/bundled-test-harness/assets/{evaluate-module-test-Bm6adsJS.js → evaluate-module-test-C_F1Y9Az.js} +1 -1
  65. package/bundled-test-harness/assets/{execute-atomic-operations-test-BAB2vv15.js → execute-atomic-operations-test-D_z5eJ6K.js} +2 -2
  66. package/bundled-test-harness/assets/fallback-banner-live-delete-test-I7o8HPay.js +209 -0
  67. package/bundled-test-harness/assets/{fallback-banner-test-DpCz2idU.js → fallback-banner-test-Bh-BDHwS.js} +3 -3
  68. package/bundled-test-harness/assets/{fallback-banner-test-Md-3yTpX.js → fallback-banner-test-DSjH5ank.js} +1 -1
  69. package/bundled-test-harness/assets/{fallback-models-test-DcB9u65l.js → fallback-models-test-GjvpcpvS.js} +3 -3
  70. package/bundled-test-harness/assets/{fetch-card-json-test-CPHdklsi.js → fetch-card-json-test-BPfTOr4N.js} +2 -2
  71. package/bundled-test-harness/assets/{field-configuration-test-Da5xu3ar.js → field-configuration-test-CH1Kc0iA.js} +2 -2
  72. package/bundled-test-harness/assets/{field-markdown-domain-test-7aY4gMQ3.js → field-markdown-domain-test-COaJBBzN.js} +2 -2
  73. package/bundled-test-harness/assets/{field-markdown-primitives-test-B8UurS_m.js → field-markdown-primitives-test-C52WikZw.js} +2 -2
  74. package/bundled-test-harness/assets/{field-markdown-specialized-test-CHiWEV2t.js → field-markdown-specialized-test-Cmq-3t4u.js} +2 -2
  75. package/bundled-test-harness/assets/{field-playground-test-DBVHB2_g.js → field-playground-test-DbXri11f.js} +3 -3
  76. package/bundled-test-harness/assets/{field-support-predicates-test-i8LXzh_P.js → field-support-predicates-test-ni5pZ9sU.js} +1 -1
  77. package/bundled-test-harness/assets/{field-test-helpers-F8iX3xAt.js → field-test-helpers-BLApZo43.js} +1 -1
  78. package/bundled-test-harness/assets/{file-attachment-test-yfZsKhWQ.js → file-attachment-test-CtV6jG8f.js} +3 -3
  79. package/bundled-test-harness/assets/{file-chooser-test-JOvGg1N8.js → file-chooser-test-C9VwTWSW.js} +2 -2
  80. package/bundled-test-harness/assets/{file-def-live-reload-test-B_XsrkaB.js → file-def-live-reload-test--L4MvUj5.js} +1 -1
  81. package/bundled-test-harness/assets/{file-def-menu-items-test-CkZrFXrK.js → file-def-menu-items-test-B_dVulF7.js} +1 -1
  82. package/bundled-test-harness/assets/{file-def-navigation-test-CyO27adK.js → file-def-navigation-test-B4_pzEXy.js} +1 -1
  83. package/bundled-test-harness/assets/{file-def-serialization-test-1XrP63F8.js → file-def-serialization-test-IoGIzKST.js} +1 -1
  84. package/bundled-test-harness/assets/{file-def-test-BJEhQN1c.js → file-def-test-CT8jTLQy.js} +1 -1
  85. package/bundled-test-harness/assets/{file-tree-test-DQSPDeb2.js → file-tree-test-DQNSRISM.js} +2 -2
  86. package/bundled-test-harness/assets/{flac-audio-def-test-CeyxsGOr.js → flac-audio-def-test-CEt7tShK.js} +1 -1
  87. package/bundled-test-harness/assets/{formatted-aibot-message-test-D09eSldQ.js → formatted-aibot-message-test-DRdKZ8lg.js} +2 -2
  88. package/bundled-test-harness/assets/{formatted-user-message-test-DmX95kEo.js → formatted-user-message-test-By3DTUBk.js} +2 -2
  89. package/bundled-test-harness/assets/{freestyle-test-KaFCs8l2.js → freestyle-test-BOVAHn_7.js} +1 -1
  90. package/bundled-test-harness/assets/{full-reindex-realm-test-BCUSPZuX.js → full-reindex-realm-test-BQji9QK_.js} +2 -2
  91. package/bundled-test-harness/assets/{garbage-collection-test-BJmgY3IQ.js → garbage-collection-test-bPtmt69E.js} +1 -1
  92. package/bundled-test-harness/assets/{general-test-B5RcCakW.js → general-test-pIZFE9Ii.js} +3 -3
  93. package/bundled-test-harness/assets/{generate-example-cards-one-shot-test-Bh9_GXLK.js → generate-example-cards-one-shot-test-DtYqN3qW.js} +1 -1
  94. package/bundled-test-harness/assets/{get-available-realm-identifiers-test-C18mJr3L.js → get-available-realm-identifiers-test-BiHIbpFc.js} +2 -2
  95. package/bundled-test-harness/assets/{get-catalog-realm-identifiers-test-vDnl-arI.js → get-catalog-realm-identifiers-test-B4EVfXvp.js} +2 -2
  96. package/bundled-test-harness/assets/{get-default-writable-realm-test-Co4F_EH-.js → get-default-writable-realm-test-C2izRfTp.js} +2 -2
  97. package/bundled-test-harness/assets/{get-published-realms-test-D6auThJu.js → get-published-realms-test-CJlYS6SA.js} +1 -1
  98. package/bundled-test-harness/assets/{get-realm-of-resource-identifier-test-BeVoQztL.js → get-realm-of-resource-identifier-test-DZG0gROs.js} +2 -2
  99. package/bundled-test-harness/assets/{get-relationship-membership-state-test-Cm_VeTXw.js → get-relationship-membership-state-test-wOVStpnA.js} +1 -1
  100. package/bundled-test-harness/assets/{get-user-system-card-test-CAc-Ainy.js → get-user-system-card-test-Bf_il1b_.js} +2 -2
  101. package/bundled-test-harness/assets/{gif-image-def-test-Co2Woq8R.js → gif-image-def-test-DD4BOFUq.js} +1 -1
  102. package/bundled-test-harness/assets/{gts-file-def-test-DMhWqyxZ.js → gts-file-def-test-KrlOMcTY.js} +1 -1
  103. package/bundled-test-harness/assets/{head-format-preview-test-DPOjt1cu.js → head-format-preview-test-CGzx-i_Q.js} +2 -2
  104. package/bundled-test-harness/assets/{helpers-BIQP26gX.js → helpers-CR-27yCL.js} +1 -1
  105. package/bundled-test-harness/assets/{host-mode-service-BYjO5JXT.js → host-mode-service-BPYfmILw.js} +1 -1
  106. package/bundled-test-harness/assets/{host-mode-test-D9kRy5kW.js → host-mode-test-sjKqSasU.js} +3 -3
  107. package/bundled-test-harness/assets/{host-submode-test-Zy7-q9vh.js → host-submode-test-CvezMbrv.js} +1 -1
  108. package/bundled-test-harness/assets/{hydratable-card-test-DvgHojHD.js → hydratable-card-test-Ds6x3mv5.js} +1 -1
  109. package/bundled-test-harness/assets/{index-query-engine-test-Bk52a889.js → index-query-engine-test-DvgGBuTy.js} +1 -1
  110. package/bundled-test-harness/assets/{index-writer-test-DNeo1Uod.js → index-writer-test-BMajX3Mj.js} +1 -1
  111. package/bundled-test-harness/assets/{inspector-test-OaFEP4S0.js → inspector-test-COfLlQnO.js} +3 -3
  112. package/bundled-test-harness/assets/{instance-filter-matcher-test-PeeLVGMO.js → instance-filter-matcher-test-DUeZ6eiv.js} +1 -1
  113. package/bundled-test-harness/assets/{instantiate-card-test-C0Y8FG7w.js → instantiate-card-test-Ba3rd5Zn.js} +1 -1
  114. package/bundled-test-harness/assets/{interact-submode-creation-and-permissions-test-Cp3YiIQG.js → interact-submode-creation-and-permissions-test-Dr-clTrg.js} +4 -4
  115. package/bundled-test-harness/assets/{interact-submode-setup-CtFp9kvB.js → interact-submode-setup-D23oc2q6.js} +1 -1
  116. package/bundled-test-harness/assets/{interact-submode-test-B_JqGk2t.js → interact-submode-test-t8HEq7Bp.js} +2 -2
  117. package/bundled-test-harness/assets/{invalidate-realm-identifiers-test-Dpa0TzwS.js → invalidate-realm-identifiers-test-Bl1RP3Kp.js} +2 -2
  118. package/bundled-test-harness/assets/{invite-user-to-room-test-DXzTeCgP.js → invite-user-to-room-test-Q26QQwvj.js} +2 -2
  119. package/bundled-test-harness/assets/{isolated-render-test-DVzQEdsY.js → isolated-render-test-Bc2ASFB1.js} +1 -1
  120. package/bundled-test-harness/assets/{job-priority-header-test-J8emfVrj.js → job-priority-header-test-CDDfX3mF.js} +1 -1
  121. package/bundled-test-harness/assets/{jpg-image-def-test-D7txmQ4U.js → jpg-image-def-test-DGjpMEj5.js} +1 -1
  122. package/bundled-test-harness/assets/{json-file-def-test-C3W6amHE.js → json-file-def-test-8NlQ7NyF.js} +1 -1
  123. package/bundled-test-harness/assets/{linksto-broken-link-placeholder-test-nZIKEYDd.js → linksto-broken-link-placeholder-test-OPR5aao3.js} +2 -2
  124. package/bundled-test-harness/assets/{linksto-error-sentinel-test-E5UdAPkR.js → linksto-error-sentinel-test-DNEi2-4f.js} +1 -1
  125. package/bundled-test-harness/assets/{linksto-many-broken-link-placeholder-test-D5lhE5y-.js → linksto-many-broken-link-placeholder-test-Bl3-UMZt.js} +2 -2
  126. package/bundled-test-harness/assets/{linksto-many-per-slot-access-test-uONh3sy8.js → linksto-many-per-slot-access-test-Cv88sT3k.js} +1 -1
  127. package/bundled-test-harness/assets/{linksto-sentinel-roundtrip-test-CUbMHhoz.js → linksto-sentinel-roundtrip-test-DDrNtJgY.js} +1 -1
  128. package/bundled-test-harness/assets/{linksto-singular-js-access-contract-test-Doycge43.js → linksto-singular-js-access-contract-test-CMOxHvSS.js} +1 -1
  129. package/bundled-test-harness/assets/{live-test-pbHzyWf7.js → live-test-BfSJ7dPf.js} +6 -6
  130. package/bundled-test-harness/assets/live-test-CfcRApCW.js +2 -0
  131. package/bundled-test-harness/assets/{loader-parallel-prefetch-test-cfEJV65W.js → loader-parallel-prefetch-test-DchEbilk.js} +1 -1
  132. package/bundled-test-harness/assets/{loader-test-DZX-dw3F.js → loader-test-LyM1F2ON.js} +1 -1
  133. package/bundled-test-harness/assets/{loading-test-PwEVbSuF.js → loading-test-DrK02DRI.js} +2 -2
  134. package/bundled-test-harness/assets/{local-storage-keys-Do9I1BSV.js → local-storage-keys-C0jyxDKn.js} +4 -1
  135. package/bundled-test-harness/assets/{m4a-audio-def-test-Dkbh40DD.js → m4a-audio-def-test-B1PZDu-M.js} +1 -1
  136. package/bundled-test-harness/assets/{main-CE7KR5Ht.js → main-CrtBvhng.js} +1 -1
  137. package/bundled-test-harness/assets/{markdown-fallback-test-BHejXXnE.js → markdown-fallback-test-D32xPo5m.js} +2 -2
  138. package/bundled-test-harness/assets/{markdown-file-def-test-BOvu8beB.js → markdown-file-def-test-2_0tc-pT.js} +1 -1
  139. package/bundled-test-harness/assets/{markdown-helpers-test-Be9UUlnA.js → markdown-helpers-test-D6Ty5K6K.js} +1 -1
  140. package/bundled-test-harness/assets/{markdown-highlighting-test-D-jxOaxc.js → markdown-highlighting-test-CD22pEyx.js} +2 -2
  141. package/bundled-test-harness/assets/{markdown-preview-test-D2kl56R1.js → markdown-preview-test-BTdN_033.js} +2 -2
  142. package/bundled-test-harness/assets/{matrix-service-sliding-sync-test-Cl1D6ID4.js → matrix-service-sliding-sync-test-Co9EhDYF.js} +1 -1
  143. package/bundled-test-harness/assets/{message-service-subscription-test-OvYUTr8V.js → message-service-subscription-test-BK3W9wng.js} +2 -2
  144. package/bundled-test-harness/assets/{mock-matrix-CD6YHaHR.js → mock-matrix-Bkfl9ACG.js} +6 -2
  145. package/bundled-test-harness/assets/{mock-matrix-Dt4s2hUe.js → mock-matrix-DbxVPkSl.js} +1 -1
  146. package/bundled-test-harness/assets/{module-transpile-cache-test-Bj11UbQJ.js → module-transpile-cache-test-BFmN6_si.js} +1 -1
  147. package/bundled-test-harness/assets/{mp3-audio-def-test-C6tzxO6X.js → mp3-audio-def-test-DorbFtva.js} +1 -1
  148. package/bundled-test-harness/assets/{number-field-test-l5WRd3N9.js → number-field-test-C9F_sOf8.js} +2 -2
  149. package/bundled-test-harness/assets/{ogg-audio-def-test-CQ04xrfS.js → ogg-audio-def-test-DRXLSBVQ.js} +1 -1
  150. package/bundled-test-harness/assets/{open-create-listing-modal-test-VxITHH84.js → open-create-listing-modal-test-Yp6EOMGK.js} +1 -1
  151. package/bundled-test-harness/assets/open-image-in-new-tab-test-B-jsojF0.js +52 -0
  152. package/bundled-test-harness/assets/{open-workspace-test-goAg_TVx.js → open-workspace-test-DrkNS6zm.js} +1 -1
  153. package/bundled-test-harness/assets/{operator-mode-acceptance-test-DO3lt95I.js → operator-mode-acceptance-test-CXQkU0xV.js} +5 -5
  154. package/bundled-test-harness/assets/{operator-mode-card-catalog-test-C3e1--M7.js → operator-mode-card-catalog-test-DjTCHu2f.js} +4 -4
  155. package/bundled-test-harness/assets/{operator-mode-links-test-AWhMhHM2.js → operator-mode-links-test-EeNC7Or8.js} +4 -4
  156. package/bundled-test-harness/assets/{operator-mode-state-service-test-BICXMa5O.js → operator-mode-state-service-test-cwdudDwm.js} +2 -2
  157. package/bundled-test-harness/assets/{operator-mode-test-DMyFaXHK.js → operator-mode-test-Cdm2eu3n.js} +4 -4
  158. package/bundled-test-harness/assets/{operator-mode-ui-test-z2SU5ozt.js → operator-mode-ui-test-yWX9IF_q.js} +4 -4
  159. package/bundled-test-harness/assets/{overlay-menu-items-test-Dkulmtpn.js → overlay-menu-items-test-D2yM2xsl.js} +3 -3
  160. package/bundled-test-harness/assets/{panel-BXXk_P7h.js → panel-DBvohlmr.js} +50 -26
  161. package/bundled-test-harness/assets/{past-sessions-test-gKLwZO61.js → past-sessions-test-DqEv1zfI.js} +3 -3
  162. package/bundled-test-harness/assets/{patch-code-test-CIdB45Nv.js → patch-code-test-Y34298iq.js} +1 -1
  163. package/bundled-test-harness/assets/{patch-fields-test-CBGnqUme.js → patch-fields-test-D1aSP1q_.js} +1 -1
  164. package/bundled-test-harness/assets/{patch-instance-test-DmDpfS3p.js → patch-instance-test-DHBeFzYI.js} +1 -1
  165. package/bundled-test-harness/assets/{persist-module-inspector-view-test-D6vpSfX4.js → persist-module-inspector-view-test-DDYttEKD.js} +2 -2
  166. package/bundled-test-harness/assets/{phone-number-field-test-DogtMkDx.js → phone-number-field-test-CUY1miSH.js} +2 -2
  167. package/bundled-test-harness/assets/{playground-CMnQXTzR.js → playground-DFwsIC-9.js} +2 -2
  168. package/bundled-test-harness/assets/{png-image-def-test-BzfrYGhY.js → png-image-def-test-C9COAyWm.js} +1 -1
  169. package/bundled-test-harness/assets/{prerender-file-extract-test-C-1R1B32.js → prerender-file-extract-test-B76NnPJt.js} +1 -1
  170. package/bundled-test-harness/assets/{prerender-html-test-1XGnbGuQ.js → prerender-html-test-ImXJjrpR.js} +1 -1
  171. package/bundled-test-harness/assets/{prerender-meta-test-B02oGS-5.js → prerender-meta-test-xIFFdF1X.js} +1 -1
  172. package/bundled-test-harness/assets/{prerender-module-test-CSKywVQA.js → prerender-module-test-CoxYOMro.js} +1 -1
  173. package/bundled-test-harness/assets/{prerendered-card-search-test-Cf_Hvr4P.js → prerendered-card-search-test-BTgiRYnI.js} +1 -1
  174. package/bundled-test-harness/assets/{preview-format-test-DBKtwgvo.js → preview-format-test-DjS1vxlt.js} +3 -3
  175. package/bundled-test-harness/assets/{preview-test-dgbtaeLg.js → preview-test-CcGZEu6Y.js} +2 -2
  176. package/bundled-test-harness/assets/{publish-realm-test-B4c6TqTI.js → publish-realm-test-Cqq_X3L4.js} +2 -2
  177. package/bundled-test-harness/assets/{query-field-barrier-test-DytVxOcd.js → query-field-barrier-test-CeDBxTwq.js} +2 -2
  178. package/bundled-test-harness/assets/{query-field-error-sentinel-test-Cs2wXQuL.js → query-field-error-sentinel-test-CwOzGgRw.js} +2 -2
  179. package/bundled-test-harness/assets/{query-field-schema-test-ByfKD-mO.js → query-field-schema-test-CXt4ktVo.js} +1 -1
  180. package/bundled-test-harness/assets/{query-fields-test-SlJNtzM3.js → query-fields-test-CrsGkXWE.js} +1 -1
  181. package/bundled-test-harness/assets/{read-card-for-ai-assistant-test-BzThkf4s.js → read-card-for-ai-assistant-test-DORLxJXd.js} +2 -2
  182. package/bundled-test-harness/assets/{read-file-for-ai-assistant-test-CV5PoqSP.js → read-file-for-ai-assistant-test-DyyCSmMv.js} +2 -2
  183. package/bundled-test-harness/assets/{read-source-test-jfWyZkQO.js → read-source-test-hAUdteMO.js} +2 -2
  184. package/bundled-test-harness/assets/{read-text-file-test-Kg6tx07O.js → read-text-file-test-juQ-OJET.js} +2 -2
  185. package/bundled-test-harness/assets/{realm-oWsFVfdH.js → realm-CxU8jc8l.js} +2 -2
  186. package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-VyMT__jT.js → realm-config-routing-rule-edit-test-E5AhFXfq.js} +3 -3
  187. package/bundled-test-harness/assets/{realm-field-test-CBmQY3Va.js → realm-field-test-wqNbmdgM.js} +2 -2
  188. package/bundled-test-harness/assets/{realm-indexing-test-CQ29IEno.js → realm-indexing-test-DTuwfnZZ.js} +1 -1
  189. package/bundled-test-harness/assets/{realm-querying-test-PR_91CCq.js → realm-querying-test-ojIOXC3n.js} +1 -1
  190. package/bundled-test-harness/assets/{realm-test-C6Kw7gWx.js → realm-test-MgXPmHwc.js} +1 -1
  191. package/bundled-test-harness/assets/{reasoning-test-M4JuH0RZ.js → reasoning-test-ChZJb8sD.js} +3 -3
  192. package/bundled-test-harness/assets/{recent-files-cards-D845sggD.js → recent-files-cards-BICbCMhW.js} +1 -1
  193. package/bundled-test-harness/assets/{recent-files-test-Du5oiGDf.js → recent-files-test-Df_1aE3G.js} +2 -2
  194. package/bundled-test-harness/assets/{reindex-realm-test-BrgFBbOc.js → reindex-realm-test-DDYvNGWh.js} +2 -2
  195. package/bundled-test-harness/assets/{relationship-loading-state-test-CnCYYtmY.js → relationship-loading-state-test-C2EialRQ.js} +1 -1
  196. package/bundled-test-harness/assets/{render-component-BJwKMGDa.js → render-component-DLXpC-Bc.js} +1 -1
  197. package/bundled-test-harness/assets/{rendered-markdown-test-BvQ96-0V.js → rendered-markdown-test-DblOECt_.js} +2 -2
  198. package/bundled-test-harness/assets/{rich-markdown-field-test-neZFxfcc.js → rich-markdown-field-test-B34TJAq8.js} +2 -2
  199. package/bundled-test-harness/assets/{room-message-test-DWEcr5le.js → room-message-test-DQ2x7ymr.js} +2 -2
  200. package/bundled-test-harness/assets/{sanitize-module-list-test-B4VjLVx_.js → sanitize-module-list-test-BTFw8-Do.js} +2 -2
  201. package/bundled-test-harness/assets/{schema-editor-test-CHeST1JD.js → schema-editor-test-w7ANspy0.js} +1 -1
  202. package/bundled-test-harness/assets/{schema-generation-test-G4ZL90Sn.js → schema-generation-test-DxhNMqOe.js} +2 -2
  203. package/bundled-test-harness/assets/{scrolling-test-D3Asc3Yr.js → scrolling-test-Drdch9wf.js} +4 -4
  204. package/bundled-test-harness/assets/{search-and-choose-test-DMB-Nv1z.js → search-and-choose-test-BhIWdkFp.js} +2 -2
  205. package/bundled-test-harness/assets/{search-command-test-BNZzENdS.js → search-command-test-BlTBufTS.js} +1 -1
  206. package/bundled-test-harness/assets/{search-correlation-id-test-tM-SfbrA.js → search-correlation-id-test-BR7bFNCy.js} +1 -1
  207. package/bundled-test-harness/assets/{search-data-test-CYrjasBZ.js → search-data-test-bc2foKLa.js} +2 -2
  208. package/bundled-test-harness/assets/{search-google-images-test-DzFbLWZE.js → search-google-images-test-C96iDOxU.js} +1 -1
  209. package/bundled-test-harness/assets/{search-test-CBH8l5JD.js → search-test-iR0wammw.js} +2 -2
  210. package/bundled-test-harness/assets/{send-ai-assistant-message-test-CAlK3x0a.js → send-ai-assistant-message-test-BmJdWdzI.js} +2 -2
  211. package/bundled-test-harness/assets/{send-bot-trigger-event-test-CwI4Rkf8.js → send-bot-trigger-event-test-CJCAf2db.js} +2 -2
  212. package/bundled-test-harness/assets/{send-request-via-proxy-test-BRuk6sv0.js → send-request-via-proxy-test-DSdZppno.js} +2 -2
  213. package/bundled-test-harness/assets/{sending-test-BA2F7Hfk.js → sending-test-6i0F6n4v.js} +269 -11
  214. package/bundled-test-harness/assets/{serialization-test-DHTHfzsn.js → serialization-test-CE3TeQ4Z.js} +2 -2
  215. package/bundled-test-harness/assets/{set-user-system-card-test-Ct8xegEY.js → set-user-system-card-test-JZW2LcIA.js} +2 -2
  216. package/bundled-test-harness/assets/{setup-v4v1a2Qc.js → setup-C5QslpqI.js} +1 -1
  217. package/bundled-test-harness/assets/{setup-BfvQ1zfD.js → setup-DeQyrqyx.js} +1 -1
  218. package/bundled-test-harness/assets/{show-card-test-7VGIdTJh.js → show-card-test-B41I3EWZ.js} +3 -3
  219. package/bundled-test-harness/assets/{skills-test-NKDA1G9S.js → skills-test-Dl7uEBNz.js} +3 -3
  220. package/bundled-test-harness/assets/{spec-test-61E0gdIB.js → spec-test-DytzFxZb.js} +3 -3
  221. package/bundled-test-harness/assets/{store-BM5pUF94.js → store-CbIxTljQ.js} +30 -0
  222. package/bundled-test-harness/assets/{store-add-test-mRtjroP0.js → store-add-test-ulvv9A3X.js} +2 -2
  223. package/bundled-test-harness/assets/{store-test-CVHw6LMN.js → store-test-Dkf9wBLg.js} +77 -4
  224. package/bundled-test-harness/assets/{summarize-session-test-UZOGVM_F.js → summarize-session-test-BcXrj1r3.js} +2 -2
  225. package/bundled-test-harness/assets/{svg-image-def-test-Dqjy84jw.js → svg-image-def-test-DW1rtFSA.js} +1 -1
  226. package/bundled-test-harness/assets/{switch-submode-test-MWnyo759.js → switch-submode-test-CX0YxbVu.js} +2 -2
  227. package/bundled-test-harness/assets/{test-support-BfonQA4V.js → test-support-CCargU9V.js} +1 -1
  228. package/bundled-test-harness/assets/{tests-DQLSvmHe.js → tests-D1v0wSnN.js} +265 -263
  229. package/bundled-test-harness/assets/{text-file-def-test-DlyCDiM4.js → text-file-def-test-Bl2R6NO8.js} +1 -1
  230. package/bundled-test-harness/assets/{text-input-validator-test-Ccx-4gLo.js → text-input-validator-test-CT3c7m8B.js} +3 -3
  231. package/bundled-test-harness/assets/{text-suggestion-test-mIvJOTS7.js → text-suggestion-test-CbJWk97Q.js} +1 -1
  232. package/bundled-test-harness/assets/{theme-card-test-Bs3Q034n.js → theme-card-test-DyOWEJRn.js} +2 -2
  233. package/bundled-test-harness/assets/{transform-cards-test-BsTtRP0g.js → transform-cards-test-3PsuM2Sv.js} +2 -2
  234. package/bundled-test-harness/assets/{ts-file-def-test-DtWzgXkt.js → ts-file-def-test-BoXA3RgL.js} +1 -1
  235. package/bundled-test-harness/assets/{unpublish-realm-test-BFJEMQL7.js → unpublish-realm-test-CgiIcZ6j.js} +2 -2
  236. package/bundled-test-harness/assets/{update-room-skills-test-BrFhA3El.js → update-room-skills-test-B-BI7daL.js} +3 -3
  237. package/bundled-test-harness/assets/{use-ai-assistant-test-BsyBY6-a.js → use-ai-assistant-test-BEiEjFOH.js} +2 -2
  238. package/bundled-test-harness/assets/user-message-Bbw4pQmd.css +22 -0
  239. package/bundled-test-harness/assets/{user-message-BFN7dtqK.js → user-message-CVG3cgJq.js} +2 -2
  240. package/bundled-test-harness/assets/{validate-realm-test-DQlQ-pWZ.js → validate-realm-test-DBx-3YG9.js} +2 -2
  241. package/bundled-test-harness/assets/{wav-audio-def-test-BZ0oLTT1.js → wav-audio-def-test-CPJl6Hpr.js} +1 -1
  242. package/bundled-test-harness/assets/{webp-image-def-test-tuOTQeTt.js → webp-image-def-test-Bh3SOpDa.js} +1 -1
  243. package/bundled-test-harness/assets/{workspace-chooser-delete-test-D_Gp78-R.js → workspace-chooser-delete-test-1n1lqK_X.js} +3 -3
  244. package/bundled-test-harness/assets/{workspace-chooser-test-CuJ4pgJh.js → workspace-chooser-test-wcKYsTgx.js} +1 -1
  245. package/bundled-test-harness/assets/{workspace-delete-multiple-test-BUmKPHGp.js → workspace-delete-multiple-test-DlXWFVK1.js} +1 -1
  246. package/bundled-test-harness/assets/{write-binary-file-test-D1h4TED_.js → write-binary-file-test-BkADCn85.js} +2 -2
  247. package/bundled-test-harness/assets/{write-text-file-test-DKA9TpIm.js → write-text-file-test-C9K0doTU.js} +2 -2
  248. package/bundled-test-harness/index.html +12 -12
  249. package/bundled-test-harness/tests/index.html +15 -15
  250. package/bundled-types/host-app/components/ai-assistant/chat-input/index.gts +2 -1
  251. package/bundled-types/host-app/components/ai-assistant/message/user-message.gts +6 -2
  252. package/bundled-types/host-app/components/matrix/room.gts +115 -44
  253. package/bundled-types/host-app/lib/matrix-classes/message-builder.ts +13 -0
  254. package/bundled-types/host-app/services/local-persistence-service.ts +179 -0
  255. package/bundled-types/host-app/services/matrix-service.ts +372 -1
  256. package/bundled-types/host-app/services/store.ts +70 -0
  257. package/bundled-types/host-app/utils/local-storage-keys.ts +2 -0
  258. package/bundled-types/host-tests/helpers/mock-matrix/_client.ts +3 -0
  259. package/bundled-types/host-tests/helpers/mock-matrix/_utils.ts +3 -0
  260. package/bundled-types/host-tests/helpers/mock-matrix.ts +1 -0
  261. package/dist/index.js +246 -242
  262. package/package.json +3 -3
  263. package/src/commands/realm/index.ts +2 -0
  264. package/src/commands/realm/ingest-card.ts +567 -0
  265. package/src/commands/realm/pull.ts +9 -13
  266. package/src/commands/realm/push.ts +10 -14
  267. package/src/commands/realm/status.ts +14 -18
  268. package/src/commands/realm/sync.ts +9 -13
  269. package/src/lib/auth-resolver.ts +15 -2
  270. package/bundled-test-harness/assets/adapter-Dk9jvNQb.js +0 -2
  271. package/bundled-test-harness/assets/live-test-B7uB4aVp.js +0 -2
  272. package/bundled-test-harness/assets/user-message-B8olA3Ml.css +0 -18
  273. /package/bundled-test-harness/assets/{ai-assistant-panel-service-test-B2pqk_1r.js → ai-assistant-panel-service-test-DEeul-zv.js} +0 -0
  274. /package/bundled-test-harness/assets/{amd-transpile-test-ftXbwnFz.js → amd-transpile-test-DmEkMdCo.js} +0 -0
  275. /package/bundled-test-harness/assets/{apply-boxel-formatting-test-BSzr4sNI.js → apply-boxel-formatting-test-RixVcq5N.js} +0 -0
  276. /package/bundled-test-harness/assets/{auth-error-guard-test-BxIq12aN.js → auth-error-guard-test-beazl6s5.js} +0 -0
  277. /package/bundled-test-harness/assets/{bfm-card-references-test-6aAhfBzH.js → bfm-card-references-test-IEbg0jo-.js} +0 -0
  278. /package/bundled-test-harness/assets/{cached-fetch-test-CPr-eiq_.js → cached-fetch-test-DlnnpQGz.js} +0 -0
  279. /package/bundled-test-harness/assets/{card-directory-name-test-BS8WD3oH.js → card-directory-name-test-QKl1Ykz6.js} +0 -0
  280. /package/bundled-test-harness/assets/{card-search-query-builder-test-zp6muUB1.js → card-search-query-builder-test-BWc5lDv3.js} +0 -0
  281. /package/bundled-test-harness/assets/{code-patching-test-BZPvPsMr.js → code-patching-test-BRNMumI6.js} +0 -0
  282. /package/bundled-test-harness/assets/{code-semantics-service-test-BBjJ3EF3.js → code-semantics-service-test-CJOSUAQH.js} +0 -0
  283. /package/bundled-test-harness/assets/{command-definitions-test-BcMJzIBM.js → command-definitions-test-De0BMqHI.js} +0 -0
  284. /package/bundled-test-harness/assets/{convert-to-class-name-test-DmF3wUKb.js → convert-to-class-name-test-B7ILkHei.js} +0 -0
  285. /package/bundled-test-harness/assets/{extract-css-variables-test-FIZxFxaL.js → extract-css-variables-test-Di5CFXG-.js} +0 -0
  286. /package/bundled-test-harness/assets/{fetcher-test-g2cjjXxV.js → fetcher-test-Cb8cS9JN.js} +0 -0
  287. /package/bundled-test-harness/assets/{field-path-parser-test-DkY-DFQN.js → field-path-parser-test-Db4kG7EB.js} +0 -0
  288. /package/bundled-test-harness/assets/{file-def-manager-canonicalize-test-Dlf4HlLX.js → file-def-manager-canonicalize-test-Cq5B5KN4.js} +0 -0
  289. /package/bundled-test-harness/assets/{generate-css-variables-test-De4LPdBt.js → generate-css-variables-test-BahavIHR.js} +0 -0
  290. /package/bundled-test-harness/assets/{get-type-refs-from-filter-test-DmDF_dTY.js → get-type-refs-from-filter-test-CH5flf8B.js} +0 -0
  291. /package/bundled-test-harness/assets/{last-modified-date-test-C2hEJ3xU.js → last-modified-date-test-C_jV0b05.js} +0 -0
  292. /package/bundled-test-harness/assets/{limited-set-test-SLbA1cwS.js → limited-set-test-CcpIJCrn.js} +0 -0
  293. /package/bundled-test-harness/assets/{loader-icon-error-test-DTo5t1OQ.js → loader-icon-error-test-Bc_L-0Zb.js} +0 -0
  294. /package/bundled-test-harness/assets/{loader-retry-test-CPFmHSUN.js → loader-retry-test-DQ0E0a0N.js} +0 -0
  295. /package/bundled-test-harness/assets/{login-error-text-test-BGvtn9op.js → login-error-text-test-BsNV9TOq.js} +0 -0
  296. /package/bundled-test-harness/assets/{marked-sync-test-CaZYJo4x.js → marked-sync-test-JSqOc6hu.js} +0 -0
  297. /package/bundled-test-harness/assets/{mutex-test-p2qp1xRj.js → mutex-test-BDkeJutn.js} +0 -0
  298. /package/bundled-test-harness/assets/{plan-install-test-CrYUs1-G.js → plan-install-test-fUZIttPZ.js} +0 -0
  299. /package/bundled-test-harness/assets/{qs-test-DEH8SHFS.js → qs-test-CminVD53.js} +0 -0
  300. /package/bundled-test-harness/assets/{query-field-normalization-test-DrqBkUxD.js → query-field-normalization-test-B9alzE_u.js} +0 -0
  301. /package/bundled-test-harness/assets/{queue-test-CS3aOeHM.js → queue-test-BvWT6K7Z.js} +0 -0
  302. /package/bundled-test-harness/assets/{realm-index-card-id-test-FV_gOG_K.js → realm-index-card-id-test-hvCyEpGZ.js} +0 -0
  303. /package/bundled-test-harness/assets/{realm-paths-test-CvXB4BUZ.js → realm-paths-test-DrwpPXyh.js} +0 -0
  304. /package/bundled-test-harness/assets/{render-component-BabSF5nE.js → render-component-DY19erxA.js} +0 -0
  305. /package/bundled-test-harness/assets/{render-error-test-CvMDARjN.js → render-error-test-BC4QmstW.js} +0 -0
  306. /package/bundled-test-harness/assets/{render-service-test-DRCvv7lo.js → render-service-test-BkCkB3a2.js} +0 -0
  307. /package/bundled-test-harness/assets/{render-timer-stub-test-CVa_rjXp.js → render-timer-stub-test-cnMPidgA.js} +0 -0
  308. /package/bundled-test-harness/assets/{search-cache-key-test-r83Xl6Io.js → search-cache-key-test-DI0DKzU5.js} +0 -0
  309. /package/bundled-test-harness/assets/{search-in-flight-key-test-BmqFzX6o.js → search-in-flight-key-test-DyRDbEX1.js} +0 -0
  310. /package/bundled-test-harness/assets/{unified-search-results-test-D9v-CCog.js → unified-search-results-test-BF8Dps_j.js} +0 -0
  311. /package/bundled-test-harness/assets/{url-test-DtekKUme.js → url-test-DkEL_mbR.js} +0 -0
  312. /package/bundled-test-harness/assets/{workspace-delete-summary-test-B8qyNd7w.js → workspace-delete-summary-test-B7rnzX95.js} +0 -0
@@ -126,6 +126,10 @@ import type CardService from './card-service';
126
126
  import type CommandService from './command-service';
127
127
  import type LoaderService from './loader-service';
128
128
  import type LocalPersistenceService from './local-persistence-service';
129
+ import type {
130
+ PendingSendStatus,
131
+ StoredPendingFile,
132
+ } from './local-persistence-service';
129
133
  import type LoggerService from './logger-service';
130
134
  import type MatrixSDKLoader from './matrix-sdk-loader';
131
135
  import type { ExtendedClient, ExtendedMatrixSDK } from './matrix-sdk-loader';
@@ -208,12 +212,20 @@ export default class MatrixService extends Service {
208
212
  private slidingSync: SlidingSync | undefined;
209
213
  private aiRoomIds: Set<string> = new Set();
210
214
  private restoredDraftRooms = new Set<string>();
215
+ private hydratedPendingSendRooms = new Set<string>();
211
216
  @tracked private _isLoadingMoreAIRooms = false;
212
217
  private initialSyncCompleted = false;
213
218
  private initialSyncCompletedDeferred = new Deferred<void>();
214
219
  private roomsWaitingForSync: Map<string, Deferred<void>> = new Map();
215
220
  @tracked private _systemCard: SystemCard | undefined;
216
221
  @tracked private _systemCardLoadFailed = false;
222
+ private _userChoiceId: string | undefined;
223
+ private _systemCardInvalidationUnsub: (() => void) | undefined;
224
+ // Sticky "the active SystemCard was deleted in-session" signal. Bridges the
225
+ // synchronous failure detection in `onSystemCardInvalidated` with the
226
+ // asynchronous re-entry into `setSystemCard(undefined)` from the matrix
227
+ // account-data echo. Cleared whenever `setSystemCard` resolves a card.
228
+ private _systemCardWasLost = false;
217
229
  agentId: string | undefined;
218
230
 
219
231
  constructor(owner: Owner) {
@@ -1251,6 +1263,136 @@ export default class MatrixService extends Service {
1251
1263
  return response;
1252
1264
  }
1253
1265
 
1266
+ // Synthesize a user-message event at click-time and push it into the room's
1267
+ // events list so the pending bubble renders without waiting for the pre-send
1268
+ // pipeline (skill / command / card / file uploads) or for matrix-js-sdk to
1269
+ // emit its native local echo. The synthetic event's id is `local-${cgi}`;
1270
+ // when matrix-js-sdk's real local echo eventually arrives in
1271
+ // processDecryptedEvent, the cgi→oldEventId bridge there replaces the
1272
+ // synthetic in-place so consumers iterating `roomData.events` never see both.
1273
+ async addOptimisticEvent(
1274
+ roomId: string,
1275
+ content: {
1276
+ body: string;
1277
+ clientGeneratedId: string;
1278
+ attachedCardIds: string[];
1279
+ attachedFiles: ReturnType<FileDef['serialize']>[];
1280
+ },
1281
+ ): Promise<number> {
1282
+ let userId = this.userId;
1283
+ if (!userId) {
1284
+ throw new Error('bug: cannot add optimistic event without a userId');
1285
+ }
1286
+ // Sort just after the tail of the existing timeline rather than using
1287
+ // `Date.now()` directly. The matrix-js-sdk and its mocks may use a clock
1288
+ // that's offset from the wall clock (mock-matrix's frozen-2024 clock is
1289
+ // the common case), and `MessageBuilder.updateMessage` early-returns when
1290
+ // the cached message's `created` is later than an incoming event — which
1291
+ // would silently drop the status transition from 'sending' to 'sent'.
1292
+ let originServerTs = this.resolveOptimisticTimestamp(roomId);
1293
+ let event: TempEvent = {
1294
+ event_id: `local-${content.clientGeneratedId}`,
1295
+ room_id: roomId,
1296
+ sender: userId,
1297
+ type: 'm.room.message',
1298
+ origin_server_ts: originServerTs,
1299
+ status: 'sending' as MatrixSDK.EventStatus,
1300
+ content: {
1301
+ msgtype: APP_BOXEL_MESSAGE_MSGTYPE,
1302
+ body: content.body,
1303
+ format: 'org.matrix.custom.html',
1304
+ clientGeneratedId: content.clientGeneratedId,
1305
+ // Deliberately omit isStreamingFinished. Setting it to `false` would
1306
+ // make `generatingResults` (which reads `!lastMessage.isStreamingFinished`)
1307
+ // misclassify the user's own bubble as "AI generating", flashing the
1308
+ // status banner over the user's pending message. Omitting the key is
1309
+ // just as effective at suppressing processDecryptedEvent's
1310
+ // code-patch-processing branch, which gates on a truthy value.
1311
+ data: {
1312
+ attachedCards: content.attachedCardIds.map((id) => ({
1313
+ sourceUrl: id,
1314
+ // MessageBuilder.attachedCardIds only reads sourceUrl; the rest of
1315
+ // SerializedFile is filled in below so attachedCardsAsFiles still
1316
+ // produces a valid FileDef object.
1317
+ name: id.split('/').pop() ?? id,
1318
+ contentType: 'application/json',
1319
+ })),
1320
+ attachedFiles: content.attachedFiles,
1321
+ context: {
1322
+ tools: [],
1323
+ functions: [],
1324
+ },
1325
+ },
1326
+ } as unknown as CardMessageContent,
1327
+ };
1328
+ await this.addRoomEvent(event);
1329
+ return originServerTs;
1330
+ }
1331
+
1332
+ // Resolve a timestamp that won't trip MessageBuilder.updateMessage's
1333
+ // `incoming.created < cached.created` early-return. Prefer the tail of the
1334
+ // existing timeline, then the SDK Room's last-active ts (matches the
1335
+ // SDK/mock clock), then wall-clock as a last resort.
1336
+ private resolveOptimisticTimestamp(roomId: string): number {
1337
+ let existingEvents = this.getRoomData(roomId)?.events ?? [];
1338
+ let maxTs = 0;
1339
+ for (let e of existingEvents) {
1340
+ let ts = (e as any).origin_server_ts;
1341
+ if (typeof ts === 'number' && ts > maxTs) {
1342
+ maxTs = ts;
1343
+ }
1344
+ }
1345
+ if (maxTs > 0) {
1346
+ return maxTs + 1;
1347
+ }
1348
+ let roomLastActive = this.client
1349
+ .getRoom?.(roomId)
1350
+ ?.getLastActiveTimestamp?.();
1351
+ if (typeof roomLastActive === 'number' && roomLastActive > 0) {
1352
+ return roomLastActive + 1;
1353
+ }
1354
+ return Date.now();
1355
+ }
1356
+
1357
+ // Patch an in-flight optimistic event's status (and optional error message)
1358
+ // Flip an in-flight pending send between 'sending' and 'not_sent' from
1359
+ // doSendMessage's catch / retry paths. Updates both the in-memory synthetic
1360
+ // event (so the rendered bubble re-runs through MessageBuilder.updateMessage)
1361
+ // and the persisted localStorage entry as one operation, so the two sources
1362
+ // of truth can't desync.
1363
+ patchPendingSend(
1364
+ roomId: string,
1365
+ clientGeneratedId: string,
1366
+ patch: { status: PendingSendStatus; errorMessage?: string },
1367
+ ) {
1368
+ let syntheticEventId = `local-${clientGeneratedId}`;
1369
+ let roomData = this.getRoomData(roomId);
1370
+ let existing = roomData?.events.find(
1371
+ (e) => e.event_id === syntheticEventId,
1372
+ );
1373
+ if (existing) {
1374
+ let nextContent: Record<string, unknown> = {
1375
+ ...(existing.content ?? {}),
1376
+ };
1377
+ if (patch.status === 'not_sent') {
1378
+ nextContent.errorMessage = patch.errorMessage ?? 'Failed to send';
1379
+ } else {
1380
+ delete nextContent.errorMessage;
1381
+ }
1382
+ let next: TempEvent = {
1383
+ ...existing,
1384
+ status: patch.status as MatrixSDK.EventStatus,
1385
+ content: nextContent as TempEvent['content'],
1386
+ };
1387
+ void this.addRoomEvent(next, syntheticEventId);
1388
+ }
1389
+ this.localPersistenceService.updatePendingSendStatus(
1390
+ roomId,
1391
+ clientGeneratedId,
1392
+ patch,
1393
+ );
1394
+ }
1395
+
1254
1396
  async sendMessage(
1255
1397
  roomId: string,
1256
1398
  body: string | undefined,
@@ -1508,10 +1650,15 @@ export default class MatrixService extends Service {
1508
1650
  this.filesToSend.clear();
1509
1651
  this.currentUserEventReadReceipts.clear();
1510
1652
  this.restoredDraftRooms = new Set();
1653
+ this.hydratedPendingSendRooms = new Set();
1511
1654
  this.aiRoomIds.clear();
1512
1655
  this.initialSyncCompleted = false;
1513
1656
  this.initialSyncCompletedDeferred = new Deferred<void>();
1514
1657
  this.roomsWaitingForSync.clear();
1658
+ this._systemCardInvalidationUnsub?.();
1659
+ this._systemCardInvalidationUnsub = undefined;
1660
+ this._userChoiceId = undefined;
1661
+ this._systemCardWasLost = false;
1515
1662
  this._systemCard = undefined;
1516
1663
  this._systemCardLoadFailed = false;
1517
1664
  this.startedAtTs = -1;
@@ -2198,8 +2345,48 @@ export default class MatrixService extends Service {
2198
2345
  this.processDecryptedEventFromAuthRoom(event);
2199
2346
  return;
2200
2347
  }
2348
+
2349
+ // cgi→oldEventId bridge: if doSendMessage previously injected a synthetic
2350
+ // optimistic event with event_id `local-${cgi}`, hand that id to addEvent
2351
+ // as oldEventId so Room.addEvent replaces the synthetic in-place. Without
2352
+ // this bridge the synthetic and the real echo would both live in
2353
+ // roomData.events and every consumer iterating `this.events` (sortedEvents,
2354
+ // usedLLMs, llmModeEvents, command/code-patch result lookups, MessageBuilder's
2355
+ // `events` argument) would double-count.
2356
+ let cgi = event.content?.clientGeneratedId as string | undefined;
2357
+ if (cgi && !oldEventId) {
2358
+ let existing = this.getRoomData(roomId)?.events.find((e) => {
2359
+ let eContent = (e as any).content;
2360
+ return (
2361
+ eContent?.clientGeneratedId === cgi &&
2362
+ typeof (e as any).event_id === 'string' &&
2363
+ (e as any).event_id.startsWith('local-')
2364
+ );
2365
+ });
2366
+ if (existing) {
2367
+ oldEventId = (existing as any).event_id;
2368
+ }
2369
+ }
2370
+
2201
2371
  await this.addRoomEvent(event, oldEventId);
2202
2372
 
2373
+ // Drop the persisted pending entry only once matrix-js-sdk has finalized
2374
+ // the send. EventStatus is null/undefined for fully-delivered events (the
2375
+ // SDK clears it after the server ack); 'sent' covers the intermediate
2376
+ // "echo accepted, awaiting ack" state. Removing earlier (e.g. on the
2377
+ // initial 'sending' local echo) would defeat a later patchPendingSend(
2378
+ // 'not_sent') because the persisted entry would already be gone, so a
2379
+ // failed send wouldn't survive a reload. 'not_sent' / 'cancelled' flow
2380
+ // through patchPendingSend instead and keep the entry around so the
2381
+ // failed bubble can be restored on reload.
2382
+ let isTerminalSent =
2383
+ event.status === null ||
2384
+ event.status === undefined ||
2385
+ (event.status as string) === 'sent';
2386
+ if (cgi && isTerminalSent && event.sender === this.userId) {
2387
+ this.localPersistenceService.removePendingSend(roomId, cgi);
2388
+ }
2389
+
2203
2390
  if (
2204
2391
  event.type === 'm.room.message' &&
2205
2392
  event.content?.[APP_BOXEL_COMMAND_REQUESTS_KEY]?.length &&
@@ -2347,6 +2534,7 @@ export default class MatrixService extends Service {
2347
2534
  }
2348
2535
 
2349
2536
  private async setSystemCard(userChoiceId: string | undefined) {
2537
+ this._userChoiceId = userChoiceId;
2350
2538
  let envDefaultId = ENV.defaultSystemCardId;
2351
2539
 
2352
2540
  if (userChoiceId && userChoiceId === this._systemCard?.id) {
@@ -2381,18 +2569,57 @@ export default class MatrixService extends Service {
2381
2569
  }
2382
2570
  }
2383
2571
 
2572
+ // Clear the post-loss signal before deriving the banner state so a
2573
+ // successful resolution in this call does not re-trip the third clause.
2574
+ if (loadedCard) {
2575
+ this._systemCardWasLost = false;
2576
+ }
2384
2577
  this._systemCardLoadFailed =
2385
- envDefaultFailed || (userChoiceFailed && !envDefaultId);
2578
+ envDefaultFailed ||
2579
+ (userChoiceFailed && !envDefaultId) ||
2580
+ (this._systemCardWasLost && !loadedCard);
2386
2581
 
2387
2582
  if (loadedCard?.id !== this._systemCard?.id) {
2583
+ this._systemCardInvalidationUnsub?.();
2584
+ this._systemCardInvalidationUnsub = undefined;
2388
2585
  this.store.dropReference(this._systemCard?.id);
2389
2586
  if (loadedCard) {
2390
2587
  this.store.addReference(loadedCard.id);
2588
+ // Capture the id in the closure — by the time the callback fires, the
2589
+ // store has evicted the card, so we cannot read it off `_systemCard`.
2590
+ let subscribedId = loadedCard.id;
2591
+ this._systemCardInvalidationUnsub =
2592
+ this.store.subscribeToCardInvalidation(subscribedId, () =>
2593
+ this.onSystemCardInvalidated(subscribedId),
2594
+ );
2391
2595
  }
2392
2596
  this._systemCard = loadedCard;
2393
2597
  }
2394
2598
  }
2395
2599
 
2600
+ // Fires when the active SystemCard is deleted in the same session (either
2601
+ // via the in-tab UI or via a matrix-auth-room invalidation originating
2602
+ // elsewhere). Re-evaluate the chain so the fallback banner surfaces or the
2603
+ // env-default silently takes over, and clear the matrix preference when the
2604
+ // dangling id was the user's own pick so it does not keep being rebroadcast.
2605
+ private onSystemCardInvalidated = async (invalidatedId: string) => {
2606
+ let wasUserChoice = this._userChoiceId === invalidatedId;
2607
+ // Drop the doomed reference so setSystemCard does not take its id-match
2608
+ // fast path against the now-evicted instance.
2609
+ this._systemCardInvalidationUnsub?.();
2610
+ this._systemCardInvalidationUnsub = undefined;
2611
+ this.store.dropReference(this._systemCard?.id);
2612
+ this._systemCard = undefined;
2613
+ // Sticky signal that survives the asynchronous matrix account-data echo
2614
+ // below — keeps `_systemCardLoadFailed` true through any re-entry into
2615
+ // `setSystemCard(undefined)` until a replacement card actually resolves.
2616
+ this._systemCardWasLost = true;
2617
+ await this.setSystemCard(this._userChoiceId);
2618
+ if (wasUserChoice) {
2619
+ await this.setUserSystemCard(undefined);
2620
+ }
2621
+ };
2622
+
2396
2623
  async setUserSystemCard(systemCardId: string | undefined) {
2397
2624
  // This sets the users account data for their preferred system card
2398
2625
  // If there is none, we fall back to the default
@@ -2454,6 +2681,132 @@ export default class MatrixService extends Service {
2454
2681
  }
2455
2682
  }
2456
2683
 
2684
+ // Hydrate persisted optimistic sends (from a prior tab/session) into the
2685
+ // room's events list before matrix-js-sdk's /sync delivers any real echo.
2686
+ // Real echoes that match by clientGeneratedId reconcile through the bridge
2687
+ // in processDecryptedEvent; entries left in 'not_sent' surface the retry alert.
2688
+ ensurePendingSendsHydrated(roomId: string) {
2689
+ if (this.hydratedPendingSendRooms.has(roomId)) {
2690
+ return;
2691
+ }
2692
+ let userId = this.userId;
2693
+ if (!userId) {
2694
+ // Don't mark the room hydrated — a later call (once login completes)
2695
+ // must be free to try again.
2696
+ return;
2697
+ }
2698
+ let entries = this.localPersistenceService.getPendingSends(roomId);
2699
+ if (entries.length === 0) {
2700
+ this.hydratedPendingSendRooms.add(roomId);
2701
+ return;
2702
+ }
2703
+ this.hydratedPendingSendRooms.add(roomId);
2704
+ for (let entry of entries) {
2705
+ // Any entry persisted as 'sending' at hydration time is orphaned:
2706
+ // matrix-js-sdk has no live pending event for it (a fresh tab/session
2707
+ // has an empty in-memory queue), so nothing will ever reconcile it.
2708
+ // Flip it to 'not_sent' so the retry alert surfaces and canSend can
2709
+ // unblock once the user dismisses or retries.
2710
+ let effectiveStatus: PendingSendStatus =
2711
+ entry.status === 'sending' ? 'not_sent' : entry.status;
2712
+ let effectiveErrorMessage =
2713
+ effectiveStatus === 'not_sent'
2714
+ ? (entry.errorMessage ?? 'Send interrupted — retry')
2715
+ : entry.errorMessage;
2716
+ if (effectiveStatus !== entry.status) {
2717
+ this.localPersistenceService.updatePendingSendStatus(
2718
+ roomId,
2719
+ entry.clientGeneratedId,
2720
+ { status: effectiveStatus, errorMessage: effectiveErrorMessage },
2721
+ );
2722
+ }
2723
+ let event: TempEvent = {
2724
+ event_id: `local-${entry.clientGeneratedId}`,
2725
+ room_id: roomId,
2726
+ sender: userId,
2727
+ type: 'm.room.message',
2728
+ origin_server_ts: entry.createdAt || Date.now(),
2729
+ status: effectiveStatus as MatrixSDK.EventStatus,
2730
+ content: {
2731
+ msgtype: APP_BOXEL_MESSAGE_MSGTYPE,
2732
+ body: entry.body,
2733
+ format: 'org.matrix.custom.html',
2734
+ clientGeneratedId: entry.clientGeneratedId,
2735
+ ...(effectiveStatus === 'not_sent' && effectiveErrorMessage
2736
+ ? { errorMessage: effectiveErrorMessage }
2737
+ : {}),
2738
+ data: {
2739
+ attachedCards: entry.attachedCardIds.map((id) => ({
2740
+ sourceUrl: id,
2741
+ name: id.split('/').pop() ?? id,
2742
+ contentType: 'application/json',
2743
+ })),
2744
+ attachedFiles: entry.attachedFiles,
2745
+ context: { tools: [], functions: [] },
2746
+ },
2747
+ } as unknown as CardMessageContent,
2748
+ };
2749
+ void this.addRoomEvent(event);
2750
+ }
2751
+ }
2752
+
2753
+ persistOptimisticSend(
2754
+ roomId: string,
2755
+ entry: {
2756
+ clientGeneratedId: string;
2757
+ body: string;
2758
+ attachedCardIds: string[];
2759
+ attachedFiles: ReturnType<FileDef['serialize']>[];
2760
+ createdAt: number;
2761
+ },
2762
+ ) {
2763
+ this.localPersistenceService.upsertPendingSend(roomId, {
2764
+ clientGeneratedId: entry.clientGeneratedId,
2765
+ body: entry.body,
2766
+ attachedCardIds: entry.attachedCardIds,
2767
+ attachedFiles: entry.attachedFiles.map(serializeFileForPersistence),
2768
+ createdAt: entry.createdAt,
2769
+ status: 'sending',
2770
+ });
2771
+ }
2772
+
2773
+ // Look up matrix-js-sdk's view of an outgoing send by clientGeneratedId.
2774
+ // Used by doSendMessage's catch block to detect the inverse delivery race
2775
+ // (sendEvent succeeded server-side but a downstream throw escaped before the
2776
+ // local echo reconciled) — in that case the bubble must stay in 'sending'
2777
+ // and let matrix's reconciliation finish, not flash 'not_sent'.
2778
+ findPendingMatrixEventStatus(
2779
+ roomId: string,
2780
+ clientGeneratedId: string,
2781
+ ): MatrixSDK.EventStatus | null | undefined {
2782
+ let room = this.client.getRoom(roomId);
2783
+ if (!room) {
2784
+ return undefined;
2785
+ }
2786
+ // Optional-chained — the mock Room in tests doesn't implement
2787
+ // getPendingEvents. The real SDK Room always does.
2788
+ let pending = room.getPendingEvents?.() ?? [];
2789
+ let matches = pending.filter((e) => {
2790
+ let c = e.getContent() as { clientGeneratedId?: string };
2791
+ return c?.clientGeneratedId === clientGeneratedId;
2792
+ });
2793
+ if (matches.length > 0) {
2794
+ return matches[matches.length - 1].status ?? null;
2795
+ }
2796
+ // Not in the SDK's pending list — could be already-sent or never-attempted.
2797
+ let live = room
2798
+ .getLiveTimeline()
2799
+ .getEvents()
2800
+ .filter((e) => {
2801
+ let c = e.getContent() as { clientGeneratedId?: string };
2802
+ return c?.clientGeneratedId === clientGeneratedId;
2803
+ });
2804
+ if (live.length > 0) {
2805
+ return live[live.length - 1].status ?? null;
2806
+ }
2807
+ return undefined;
2808
+ }
2809
+
2457
2810
  async getPromptParts(roomId: string) {
2458
2811
  const roomResource = this.roomResourcesCache.get(roomId);
2459
2812
  if (!roomResource) {
@@ -2500,6 +2853,24 @@ async function getStorage() {
2500
2853
  return storage;
2501
2854
  }
2502
2855
 
2856
+ function serializeFileForPersistence(
2857
+ f: ReturnType<FileDef['serialize']>,
2858
+ ): StoredPendingFile {
2859
+ // Conditional spreads avoid emitting `{ name: undefined }` keys, which
2860
+ // matters under exactOptionalPropertyTypes — see sanitizePendingFile in
2861
+ // local-persistence-service.ts for the symmetric reader.
2862
+ return {
2863
+ sourceUrl: f.sourceUrl,
2864
+ ...(f.name ? { name: f.name } : {}),
2865
+ ...(f.url ? { url: f.url } : {}),
2866
+ ...(f.contentType ? { contentType: f.contentType } : {}),
2867
+ ...(f.contentHash ? { contentHash: f.contentHash } : {}),
2868
+ ...(typeof f.contentSize === 'number'
2869
+ ? { contentSize: f.contentSize }
2870
+ : {}),
2871
+ } as StoredPendingFile;
2872
+ }
2873
+
2503
2874
  declare module '@ember/service' {
2504
2875
  interface Registry {
2505
2876
  'matrix-service': MatrixService;
@@ -224,6 +224,7 @@ export default class StoreService extends Service implements StoreInterface {
224
224
  @service declare private operatorModeStateService: OperatorModeStateService;
225
225
  @service declare private realmServer: RealmServerService;
226
226
  private subscriptions: Map<string, { unsubscribe: () => void }> = new Map();
227
+ private cardInvalidationSubscribers: Map<string, Set<() => void>> = new Map();
227
228
  private referenceCount: ReferenceCount = new Map();
228
229
  private newReferencePromises: Promise<void>[] = [];
229
230
  private autoSaveStates: TrackedMap<string, AutoSaveState> = new TrackedMap();
@@ -323,6 +324,7 @@ export default class StoreService extends Service implements StoreInterface {
323
324
  resetState() {
324
325
  clearInterval(this.gcInterval);
325
326
  this.subscriptions = new Map();
327
+ this.cardInvalidationSubscribers = new Map();
326
328
  this.onSaveSubscriber = undefined;
327
329
  this.referenceCount = new Map();
328
330
  this.newReferencePromises = [];
@@ -396,6 +398,65 @@ export default class StoreService extends Service implements StoreInterface {
396
398
  this.reestablishReferences.perform();
397
399
  }
398
400
 
401
+ // Notify-on-delete for callers that hold a card by direct JS reference rather
402
+ // than by linksTo. `consumersOf` only walks linksTo refs, so a direct holder
403
+ // (e.g. MatrixService's `_systemCard`) would otherwise stay pinned to a
404
+ // now-evicted instance until the next reload. Subscribers fire from both
405
+ // delete paths — `delete()` (in-tab UI) and the `reloadTask` 404 branch
406
+ // (matrix-auth-room invalidation for cross-tab / cross-machine deletes).
407
+ subscribeToCardInvalidation(id: string, cb: () => void): () => void {
408
+ let normalizedId = asURL(id, this.network.virtualNetwork);
409
+ let subscribers = this.cardInvalidationSubscribers.get(normalizedId);
410
+ if (!subscribers) {
411
+ subscribers = new Set();
412
+ this.cardInvalidationSubscribers.set(normalizedId, subscribers);
413
+ }
414
+ subscribers.add(cb);
415
+ return () => {
416
+ let current = this.cardInvalidationSubscribers.get(normalizedId);
417
+ if (!current) {
418
+ return;
419
+ }
420
+ current.delete(cb);
421
+ if (current.size === 0) {
422
+ this.cardInvalidationSubscribers.delete(normalizedId);
423
+ }
424
+ };
425
+ }
426
+
427
+ private notifyCardInvalidationSubscribers(id: string) {
428
+ let normalizedId = asURL(id, this.network.virtualNetwork);
429
+ let subscribers = this.cardInvalidationSubscribers.get(normalizedId);
430
+ if (!subscribers) {
431
+ return;
432
+ }
433
+ // Snapshot to tolerate unsubscribe-from-callback without skipping siblings.
434
+ // Subscribers may be async — catch rejections that escape the synchronous
435
+ // try/catch so a failure in one handler does not become an unhandled
436
+ // promise rejection or starve sibling handlers.
437
+ for (let cb of [...subscribers]) {
438
+ try {
439
+ let maybePromise = cb() as unknown;
440
+ if (
441
+ maybePromise &&
442
+ typeof (maybePromise as PromiseLike<unknown>).then === 'function'
443
+ ) {
444
+ (maybePromise as Promise<unknown>).catch((err) =>
445
+ console.error(
446
+ `card invalidation subscriber for ${normalizedId} rejected`,
447
+ err,
448
+ ),
449
+ );
450
+ }
451
+ } catch (err) {
452
+ console.error(
453
+ `card invalidation subscriber for ${normalizedId} threw`,
454
+ err,
455
+ );
456
+ }
457
+ }
458
+ }
459
+
399
460
  dropReference(id: string | undefined) {
400
461
  if (!id) {
401
462
  return;
@@ -809,6 +870,11 @@ export default class StoreService extends Service implements StoreInterface {
809
870
  }
810
871
  }
811
872
  await this.cardService.fetchJSON(id, { method: 'DELETE' });
873
+ // Notify direct-reference holders (e.g. MatrixService's `_systemCard`)
874
+ // only AFTER the server DELETE completes — these subscribers typically
875
+ // re-evaluate by calling `store.get(id)`, which is cache-first and would
876
+ // otherwise refetch the still-extant file and miss the deletion.
877
+ this.notifyCardInvalidationSubscribers(id);
812
878
  }
813
879
 
814
880
  async patch<T extends CardDef = CardDef>(
@@ -1660,6 +1726,10 @@ export default class StoreService extends Service implements StoreInterface {
1660
1726
  for (let consumer of consumers) {
1661
1727
  api.notifyLinksToTargetDeleted(consumer, instance.id);
1662
1728
  }
1729
+ // Notify direct-reference holders after the local eviction so their
1730
+ // re-evaluation does not return the cached pre-delete instance.
1731
+ // (The server is already gone — we got here from a 404 reload.)
1732
+ this.notifyCardInvalidationSubscribers(instance.id);
1663
1733
  }
1664
1734
  } finally {
1665
1735
  this.finishTrackingCardLoad(instance.id, reloadTracker);
@@ -7,6 +7,7 @@ export const CodeModePanelHeights = 'code-mode-panel-heights';
7
7
  export const ModuleInspectorSelections = 'code-mode-panel-selections';
8
8
  export const SessionLocalStorageKey = 'boxel-session';
9
9
  export const AiAssistantMessageDrafts = 'ai-assistant-message-drafts';
10
+ export const AiAssistantPendingSends = 'ai-assistant-pending-sends';
10
11
  export const PlaygroundSelections = 'playground-selections';
11
12
  export const SpecSelection = 'spec-selection';
12
13
  export const RecentCards = 'recent-cards';
@@ -25,4 +26,5 @@ export function clearLocalStorage(storage: Storage | undefined) {
25
26
  storage?.removeItem(RecentFiles);
26
27
  storage?.removeItem(ScrollPositions);
27
28
  storage?.removeItem(AiAssistantMessageDrafts);
29
+ storage?.removeItem(AiAssistantPendingSends);
28
30
  }
@@ -498,6 +498,9 @@ export class MockClient implements ExtendedClient {
498
498
  let localEvent = new MatrixEvent(localEventData);
499
499
  localEvent.setStatus('sending' as MatrixSDK.EventStatus.SENDING);
500
500
  this.emitEvent(localEvent);
501
+ if (this.sdkOpts.sendEventInterceptor) {
502
+ await this.sdkOpts.sendEventInterceptor();
503
+ }
501
504
  if (content.body?.match(/SENDING_DELAY_THEN_/)) {
502
505
  await new Promise((resolve) => setTimeout(resolve, 1000));
503
506
  }
@@ -131,6 +131,9 @@ export class MockUtils {
131
131
  setUploadContentInterceptor = (fn: (() => Promise<void>) | undefined) => {
132
132
  this.testState.opts!.uploadContentInterceptor = fn;
133
133
  };
134
+ setSendEventInterceptor = (fn: (() => Promise<void>) | undefined) => {
135
+ this.testState.opts!.sendEventInterceptor = fn;
136
+ };
134
137
 
135
138
  setRoomState = (
136
139
  roomId: string,
@@ -31,6 +31,7 @@ export interface Config {
31
31
  directRooms?: string[];
32
32
  systemCardAccountData?: { id?: string };
33
33
  uploadContentInterceptor?: () => Promise<void>;
34
+ sendEventInterceptor?: () => Promise<void>;
34
35
  workspaceFavorites?: string[];
35
36
  }
36
37