@cardstack/boxel-cli 0.3.2-unstable.61 → 0.4.0-unstable.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-realms/base/card-api.gts +2 -0
- package/bundled-realms/base/components/cards-grid-layout.gts +24 -2
- package/bundled-realms/base/field-component.gts +16 -4
- package/bundled-realms/base/links-to-editor.gts +27 -3
- package/bundled-realms/base/realm-config.gts +18 -1
- package/bundled-test-harness/assets/adapter-unm-Xq4g.js +2 -0
- 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
- package/bundled-test-harness/assets/{add-workspace-tMjv_Ar4.js → add-workspace-DBDTvtP2.js} +3 -3
- package/bundled-test-harness/assets/{add-workspace-test-BMKxSlaC.js → add-workspace-test-CE21v7jK.js} +3 -3
- package/bundled-test-harness/assets/{ai-assistant-test-C3LjW9Uz.js → ai-assistant-test-DSyMR0hY.js} +8 -7
- package/bundled-test-harness/assets/{ai-function-generation-test-WqD9vlzP.js → ai-function-generation-test-BkTvuCnq.js} +1 -1
- package/bundled-test-harness/assets/{ai-module-creation-test-CeP1V90-.js → ai-module-creation-test-zY83EN93.js} +3 -3
- package/bundled-test-harness/assets/{aibot-message-CiwsV-h8.js → aibot-message-BfRah4Lm.js} +2 -2
- package/bundled-test-harness/assets/{app-C8fZHSIY.js → app-CPRVydcd.js} +321 -33
- package/bundled-test-harness/assets/{apply-markdown-edit-test-VkN9mVg4.js → apply-markdown-edit-test-CpeCS12T.js} +2 -2
- package/bundled-test-harness/assets/{apply-search-replace-block-test-C4GiLUbz.js → apply-search-replace-block-test-Czoi47xr.js} +1 -1
- package/bundled-test-harness/assets/{auth-service-worker-registration-CGUqW_lr.js → auth-service-worker-registration-C3rAs9Yi.js} +1 -1
- package/bundled-test-harness/assets/{auth-service-worker-test-DjVH_n4v.js → auth-service-worker-test-DTHQyoUg.js} +3 -3
- package/bundled-test-harness/assets/{authed-fetch-test-PT9AWQEk.js → authed-fetch-test-BRqybmXe.js} +2 -2
- package/bundled-test-harness/assets/{avif-image-def-test-BMFnvMFY.js → avif-image-def-test-BVwv4Ahc.js} +1 -1
- package/bundled-test-harness/assets/{basic-test-B5EcLZRP.js → basic-test-Dbky79J2.js} +1 -1
- package/bundled-test-harness/assets/{binary-upload-dedupe-test-BvQVNF95.js → binary-upload-dedupe-test-nnaYqiTh.js} +3 -3
- package/bundled-test-harness/assets/{bot-registration-test-Cy1HY7PT.js → bot-registration-test-zrufhFTo.js} +2 -2
- package/bundled-test-harness/assets/{box-test-BTOPLQ3k.js → box-test-B85wfMJn.js} +1 -1
- package/bundled-test-harness/assets/{brand-guide-attachments-test-C4R_z8N5.js → brand-guide-attachments-test-C8-n-naq.js} +2 -2
- package/bundled-test-harness/assets/{brand-guide-custom-css-test-Me-k86li.js → brand-guide-custom-css-test-B2fmvFp4.js} +2 -2
- package/bundled-test-harness/assets/{brand-logo-mark-field-test-DcCSpYJq.js → brand-logo-mark-field-test-CJ4s6jjd.js} +2 -2
- package/bundled-test-harness/assets/{broken-link-template-test-BRD2BX45.js → broken-link-template-test-BHXrPxQ6.js} +2 -2
- package/bundled-test-harness/assets/{can-read-realm-test-_flXUfS4.js → can-read-realm-test-mHnz9-_s.js} +2 -2
- package/bundled-test-harness/assets/{cancel-indexing-job-test-0JyPszPo.js → cancel-indexing-job-test-Drx2ghoA.js} +2 -2
- package/bundled-test-harness/assets/{card-api-test-BpeMpeQ0.js → card-api-test-C0HrvAuC.js} +3 -3
- package/bundled-test-harness/assets/{card-basics-test-C-UCeun-.js → card-basics-test-CvITmKK-.js} +3 -3
- package/bundled-test-harness/assets/{card-catalog-test-4K3_LE47.js → card-catalog-test-CWkfBRuQ.js} +3 -3
- package/bundled-test-harness/assets/{card-copy-test-BFFsV3G-.js → card-copy-test-Co_MPCIJ.js} +3 -3
- package/bundled-test-harness/assets/{card-def-field-def-relationships-test-CRjFV5pq.js → card-def-field-def-relationships-test-7e-g4qJs.js} +3 -3
- package/bundled-test-harness/assets/{card-def-menu-items-test-DQNnU_0P.js → card-def-menu-items-test-DLO6TEhC.js} +1 -1
- package/bundled-test-harness/assets/{card-delete-test-DOyt5y-x.js → card-delete-test-BcOtJYm4.js} +3 -3
- package/bundled-test-harness/assets/{card-error-detail-DuFoktdn.js → card-error-detail-Q7wtuRcv.js} +2 -2
- package/bundled-test-harness/assets/{card-playground-test-CiESzD5-.js → card-playground-test-DxoIBbjx.js} +3 -3
- package/bundled-test-harness/assets/{card-search-adorn-test-DdTUl5RY.js → card-search-adorn-test-CbsnFvDF.js} +2 -2
- package/bundled-test-harness/assets/{card-search-selection-menu-test-BJFUbgA1.js → card-search-selection-menu-test-CY77b1kz.js} +2 -2
- package/bundled-test-harness/assets/{check-correctness-test-B4E7WXSZ.js → check-correctness-test-D0EYMlP7.js} +2 -2
- package/bundled-test-harness/assets/{check-domain-availability-test-BnmsW2P7.js → check-domain-availability-test-BYAkVLGj.js} +2 -2
- package/bundled-test-harness/assets/{code-patches-test-6Lvfhm1l.js → code-patches-test-BDg35i4X.js} +1 -1
- package/bundled-test-harness/assets/{code-ref-test-BWuTdZ2e.js → code-ref-test-BZGL3teK.js} +1 -1
- package/bundled-test-harness/assets/{code-submode-test-DPzE9tKe.js → code-submode-test-DIiXgCRB.js} +3 -3
- package/bundled-test-harness/assets/{codeblocks-test-MV1tHflj.js → codeblocks-test-CFR0u5-j.js} +3 -3
- package/bundled-test-harness/assets/{codemirror-editor-test-SD3gDmHw.js → codemirror-editor-test-e1Yn_b_1.js} +1 -1
- package/bundled-test-harness/assets/{color-field-test-C_7cf4Z2.js → color-field-test-okcvtdsF.js} +2 -2
- package/bundled-test-harness/assets/{commands-DoigkJc8.js → commands-BOwQjc8N.js} +3 -3
- package/bundled-test-harness/assets/{commands-calling-test-Br4sMoMf.js → commands-calling-test-BETL8EWm.js} +2 -2
- package/bundled-test-harness/assets/{commands-test-71b4Fun5.js → commands-test-BpFjXsiC.js} +3 -3
- package/bundled-test-harness/assets/{commands-test-COT9Ck-6.js → commands-test-QSW7zRvO.js} +2 -2
- package/bundled-test-harness/assets/{components-CBfd9MIo.js → components-DYC4nC4r.js} +184 -184
- package/bundled-test-harness/assets/{components-8vaKSlYm.css → components-DgK6vTbM.css} +17 -14
- package/bundled-test-harness/assets/{computed-test-BbCVTMkD.js → computed-test-C2j8r-e_.js} +2 -2
- package/bundled-test-harness/assets/{container-BVdtw4NT.js → container-DRblzvCW.js} +18 -18
- package/bundled-test-harness/assets/{convert-to-class-name-test-DmF3wUKb.js → convert-to-class-name-test-BiCrnGxA.js} +1 -1
- package/bundled-test-harness/assets/{copy-and-edit-test-1xrTe8p1.js → copy-and-edit-test-DqV_dpu_.js} +1 -1
- package/bundled-test-harness/assets/{copy-card-test-D0rXx03h.js → copy-card-test-B4dNP03f.js} +1 -1
- package/bundled-test-harness/assets/{copy-file-to-realm-test-DxW5PABL.js → copy-file-to-realm-test-oGK9EM0P.js} +1 -1
- package/bundled-test-harness/assets/{copy-source-test-Dy83btnV.js → copy-source-test-GtNFw5fv.js} +2 -2
- package/bundled-test-harness/assets/{create-file-modal-BNJHELMz.js → create-file-modal-Cfvn0u5s.js} +4 -4
- package/bundled-test-harness/assets/{create-file-test-DimDxpRl.js → create-file-test-2WPpTJ5F.js} +1 -1
- package/bundled-test-harness/assets/{create-file-test-COppMhde.js → create-file-test-HxkEMHWL.js} +2 -2
- package/bundled-test-harness/assets/{create-listing-modal-test-D57Altg2.js → create-listing-modal-test-W6LuCzaK.js} +4 -4
- package/bundled-test-harness/assets/{create-listing-pr-request-test-HJmFkx_x.js → create-listing-pr-request-test-2ZRF_IBk.js} +2 -2
- package/bundled-test-harness/assets/{create-spec-test-C-4bkoj3.js → create-spec-test-JVOisAUl.js} +1 -1
- package/bundled-test-harness/assets/{csv-file-def-test-GOmD6Ikx.js → csv-file-def-test-DIVp_7a6.js} +1 -1
- package/bundled-test-harness/assets/{date-time-fields-test-BYn57092.js → date-time-fields-test-BWdrrYdj.js} +2 -2
- package/bundled-test-harness/assets/{debug-message-test-CNzx_IFI.js → debug-message-test-CXVfUuec.js} +3 -3
- package/bundled-test-harness/assets/{diffing-test-PA40XPFB.js → diffing-test-JzXF051K.js} +1 -1
- package/bundled-test-harness/assets/{editor-test-Dg1fTno0.js → editor-test-j9znzFxy.js} +2 -2
- package/bundled-test-harness/assets/{email-field-test-rPWkRvgR.js → email-field-test-D4vZ2Qnc.js} +2 -2
- package/bundled-test-harness/assets/{enum-field-test-DjQ-sjAR.js → enum-field-test-DtZ_sOiA.js} +2 -2
- package/bundled-test-harness/assets/{error-display-test-Cp1vgWSg.js → error-display-test-B6I8CYXw.js} +2 -2
- package/bundled-test-harness/assets/{evaluate-module-test-Bm6adsJS.js → evaluate-module-test-C_F1Y9Az.js} +1 -1
- package/bundled-test-harness/assets/{execute-atomic-operations-test-BAB2vv15.js → execute-atomic-operations-test-D_z5eJ6K.js} +2 -2
- package/bundled-test-harness/assets/{externals-C65aJ_7H.js → externals-DiG6hYU9.js} +2 -2
- package/bundled-test-harness/assets/fallback-banner-live-delete-test-Bv_OBmzY.js +209 -0
- package/bundled-test-harness/assets/{fallback-banner-test-Md-3yTpX.js → fallback-banner-test-DSjH5ank.js} +1 -1
- package/bundled-test-harness/assets/{fallback-banner-test-DpCz2idU.js → fallback-banner-test-TL8jNe4f.js} +3 -3
- package/bundled-test-harness/assets/{fallback-models-test-DcB9u65l.js → fallback-models-test-DEhvKsfY.js} +3 -3
- package/bundled-test-harness/assets/{fetch-card-json-test-CPHdklsi.js → fetch-card-json-test-BPfTOr4N.js} +2 -2
- package/bundled-test-harness/assets/{field-configuration-test-Da5xu3ar.js → field-configuration-test-CH1Kc0iA.js} +2 -2
- package/bundled-test-harness/assets/{field-markdown-domain-test-7aY4gMQ3.js → field-markdown-domain-test-COaJBBzN.js} +2 -2
- package/bundled-test-harness/assets/{field-markdown-primitives-test-B8UurS_m.js → field-markdown-primitives-test-C52WikZw.js} +2 -2
- package/bundled-test-harness/assets/{field-markdown-specialized-test-CHiWEV2t.js → field-markdown-specialized-test-Cmq-3t4u.js} +2 -2
- package/bundled-test-harness/assets/{field-playground-test-DBVHB2_g.js → field-playground-test-DbXri11f.js} +3 -3
- package/bundled-test-harness/assets/{field-support-predicates-test-i8LXzh_P.js → field-support-predicates-test-ni5pZ9sU.js} +1 -1
- package/bundled-test-harness/assets/{field-test-helpers-F8iX3xAt.js → field-test-helpers-BLApZo43.js} +1 -1
- package/bundled-test-harness/assets/{file-DUbLArQi.js → file-D8hnXC1_.js} +8 -2
- package/bundled-test-harness/assets/{file-attachment-test-yfZsKhWQ.js → file-attachment-test-CkL6IaWf.js} +3 -3
- package/bundled-test-harness/assets/{file-chooser-test-JOvGg1N8.js → file-chooser-test-M1rOgltw.js} +2 -2
- package/bundled-test-harness/assets/{file-def-live-reload-test-B_XsrkaB.js → file-def-live-reload-test--L4MvUj5.js} +1 -1
- package/bundled-test-harness/assets/{file-def-menu-items-test-CkZrFXrK.js → file-def-menu-items-test-B_dVulF7.js} +1 -1
- package/bundled-test-harness/assets/{file-def-navigation-test-CyO27adK.js → file-def-navigation-test-B4_pzEXy.js} +1 -1
- package/bundled-test-harness/assets/{file-def-serialization-test-1XrP63F8.js → file-def-serialization-test-IoGIzKST.js} +1 -1
- package/bundled-test-harness/assets/{file-def-test-BJEhQN1c.js → file-def-test-CT8jTLQy.js} +1 -1
- package/bundled-test-harness/assets/{file-tree-test-DQSPDeb2.js → file-tree-test-DQNSRISM.js} +2 -2
- package/bundled-test-harness/assets/{flac-audio-def-test-CeyxsGOr.js → flac-audio-def-test-CEt7tShK.js} +1 -1
- package/bundled-test-harness/assets/{formatted-aibot-message-test-D09eSldQ.js → formatted-aibot-message-test-CNk1lVYO.js} +3 -3
- package/bundled-test-harness/assets/{formatted-user-message-test-DmX95kEo.js → formatted-user-message-test-By3DTUBk.js} +2 -2
- package/bundled-test-harness/assets/{freestyle-test-KaFCs8l2.js → freestyle-test-BOVAHn_7.js} +1 -1
- package/bundled-test-harness/assets/{full-reindex-realm-test-BCUSPZuX.js → full-reindex-realm-test-BQji9QK_.js} +2 -2
- package/bundled-test-harness/assets/{garbage-collection-test-BJmgY3IQ.js → garbage-collection-test-bPtmt69E.js} +1 -1
- package/bundled-test-harness/assets/{general-test-B5RcCakW.js → general-test-B_QwZC0y.js} +3 -3
- package/bundled-test-harness/assets/{generate-example-cards-one-shot-test-Bh9_GXLK.js → generate-example-cards-one-shot-test-DtYqN3qW.js} +1 -1
- package/bundled-test-harness/assets/{get-available-realm-identifiers-test-C18mJr3L.js → get-available-realm-identifiers-test-BiHIbpFc.js} +2 -2
- package/bundled-test-harness/assets/{get-catalog-realm-identifiers-test-vDnl-arI.js → get-catalog-realm-identifiers-test-B4EVfXvp.js} +2 -2
- package/bundled-test-harness/assets/{get-default-writable-realm-test-Co4F_EH-.js → get-default-writable-realm-test-C2izRfTp.js} +2 -2
- package/bundled-test-harness/assets/{get-published-realms-test-D6auThJu.js → get-published-realms-test-CJlYS6SA.js} +1 -1
- package/bundled-test-harness/assets/{get-realm-of-resource-identifier-test-BeVoQztL.js → get-realm-of-resource-identifier-test-DZG0gROs.js} +2 -2
- package/bundled-test-harness/assets/{get-relationship-membership-state-test-Cm_VeTXw.js → get-relationship-membership-state-test-wOVStpnA.js} +1 -1
- package/bundled-test-harness/assets/{get-user-system-card-test-CAc-Ainy.js → get-user-system-card-test-Bf_il1b_.js} +2 -2
- package/bundled-test-harness/assets/{gif-image-def-test-Co2Woq8R.js → gif-image-def-test-DD4BOFUq.js} +1 -1
- package/bundled-test-harness/assets/{gts-file-def-test-DMhWqyxZ.js → gts-file-def-test-KrlOMcTY.js} +1 -1
- package/bundled-test-harness/assets/{head-format-preview-test-DPOjt1cu.js → head-format-preview-test-CGzx-i_Q.js} +2 -2
- package/bundled-test-harness/assets/{helpers-BIQP26gX.js → helpers-CR-27yCL.js} +1 -1
- package/bundled-test-harness/assets/{host-mode-service-BYjO5JXT.js → host-mode-service-BPYfmILw.js} +1 -1
- package/bundled-test-harness/assets/{host-mode-test-D9kRy5kW.js → host-mode-test-sjKqSasU.js} +3 -3
- package/bundled-test-harness/assets/{host-submode-test-Zy7-q9vh.js → host-submode-test-CvezMbrv.js} +1 -1
- package/bundled-test-harness/assets/{hydratable-card-test-DvgHojHD.js → hydratable-card-test-Ds6x3mv5.js} +1 -1
- package/bundled-test-harness/assets/{index-query-engine-test-Bk52a889.js → index-query-engine-test-x77vbwML.js} +2 -2
- package/bundled-test-harness/assets/{index-writer-test-DNeo1Uod.js → index-writer-test-BMajX3Mj.js} +1 -1
- package/bundled-test-harness/assets/{inspector-test-OaFEP4S0.js → inspector-test-CtCAKlpG.js} +42 -5
- package/bundled-test-harness/assets/{instance-filter-matcher-test-PeeLVGMO.js → instance-filter-matcher-test-YKzjZAa3.js} +2 -2
- package/bundled-test-harness/assets/{instantiate-card-test-C0Y8FG7w.js → instantiate-card-test-Ba3rd5Zn.js} +1 -1
- package/bundled-test-harness/assets/{interact-submode-creation-and-permissions-test-Cp3YiIQG.js → interact-submode-creation-and-permissions-test-2_4tHla6.js} +4 -4
- package/bundled-test-harness/assets/{interact-submode-setup-CtFp9kvB.js → interact-submode-setup-DI2HM3S-.js} +2 -2
- package/bundled-test-harness/assets/{interact-submode-test-B_JqGk2t.js → interact-submode-test-BUKZnm-y.js} +2 -2
- package/bundled-test-harness/assets/{invalidate-realm-identifiers-test-Dpa0TzwS.js → invalidate-realm-identifiers-test-Bl1RP3Kp.js} +2 -2
- package/bundled-test-harness/assets/{invite-user-to-room-test-DXzTeCgP.js → invite-user-to-room-test-Q26QQwvj.js} +2 -2
- package/bundled-test-harness/assets/{isolated-render-test-DVzQEdsY.js → isolated-render-test-Bc2ASFB1.js} +1 -1
- package/bundled-test-harness/assets/{item-button-CAhhwhRh.js → item-button-CepLHUN-.js} +1 -1
- package/bundled-test-harness/assets/{job-priority-header-test-J8emfVrj.js → job-priority-header-test-CDDfX3mF.js} +1 -1
- package/bundled-test-harness/assets/{jpg-image-def-test-D7txmQ4U.js → jpg-image-def-test-DGjpMEj5.js} +1 -1
- package/bundled-test-harness/assets/{json-file-def-test-C3W6amHE.js → json-file-def-test-8NlQ7NyF.js} +1 -1
- package/bundled-test-harness/assets/{linksto-broken-link-placeholder-test-nZIKEYDd.js → linksto-broken-link-placeholder-test-OPR5aao3.js} +2 -2
- package/bundled-test-harness/assets/{linksto-error-sentinel-test-E5UdAPkR.js → linksto-error-sentinel-test-DNEi2-4f.js} +1 -1
- package/bundled-test-harness/assets/{linksto-many-broken-link-placeholder-test-D5lhE5y-.js → linksto-many-broken-link-placeholder-test-Bl3-UMZt.js} +2 -2
- package/bundled-test-harness/assets/{linksto-many-per-slot-access-test-uONh3sy8.js → linksto-many-per-slot-access-test-Cv88sT3k.js} +1 -1
- package/bundled-test-harness/assets/{linksto-sentinel-roundtrip-test-CUbMHhoz.js → linksto-sentinel-roundtrip-test-DDrNtJgY.js} +1 -1
- package/bundled-test-harness/assets/{linksto-singular-js-access-contract-test-Doycge43.js → linksto-singular-js-access-contract-test-CMOxHvSS.js} +1 -1
- package/bundled-test-harness/assets/{live-prerendered-search-kxxMxyHS.js → live-prerendered-search-DiFs_MHd.js} +1 -1
- package/bundled-test-harness/assets/{live-test-pbHzyWf7.js → live-test-BfSJ7dPf.js} +6 -6
- package/bundled-test-harness/assets/live-test-CfcRApCW.js +2 -0
- package/bundled-test-harness/assets/{loader-parallel-prefetch-test-cfEJV65W.js → loader-parallel-prefetch-test-DchEbilk.js} +1 -1
- package/bundled-test-harness/assets/{loader-test-DZX-dw3F.js → loader-test-LyM1F2ON.js} +1 -1
- package/bundled-test-harness/assets/{loading-test-PwEVbSuF.js → loading-test-DrK02DRI.js} +2 -2
- package/bundled-test-harness/assets/{local-storage-keys-Do9I1BSV.js → local-storage-keys-C0jyxDKn.js} +4 -1
- package/bundled-test-harness/assets/{login-ou9E1DG9.js → login-DWNfbapF.js} +1 -1
- package/bundled-test-harness/assets/{login-error-text-test-BGvtn9op.js → login-error-text-test-3lQ69Gme.js} +1 -1
- package/bundled-test-harness/assets/{m4a-audio-def-test-Dkbh40DD.js → m4a-audio-def-test-B1PZDu-M.js} +1 -1
- package/bundled-test-harness/assets/{main-CE7KR5Ht.js → main-CDat3XsY.js} +1 -1
- package/bundled-test-harness/assets/{markdown-fallback-test-BHejXXnE.js → markdown-fallback-test-D32xPo5m.js} +2 -2
- package/bundled-test-harness/assets/{markdown-file-def-test-BOvu8beB.js → markdown-file-def-test-2_0tc-pT.js} +1 -1
- package/bundled-test-harness/assets/{markdown-helpers-test-Be9UUlnA.js → markdown-helpers-test-D6Ty5K6K.js} +1 -1
- package/bundled-test-harness/assets/{markdown-highlighting-test-D-jxOaxc.js → markdown-highlighting-test-CD22pEyx.js} +2 -2
- package/bundled-test-harness/assets/{markdown-preview-CKlpPkbc.js → markdown-preview-o2AI98EN.js} +1 -1
- package/bundled-test-harness/assets/{markdown-preview-test-D2kl56R1.js → markdown-preview-test-D2YoXqUY.js} +3 -3
- package/bundled-test-harness/assets/{matrix-service-sliding-sync-test-Cl1D6ID4.js → matrix-service-sliding-sync-test-Co9EhDYF.js} +1 -1
- package/bundled-test-harness/assets/{message-service-subscription-test-OvYUTr8V.js → message-service-subscription-test-BK3W9wng.js} +2 -2
- package/bundled-test-harness/assets/{mock-matrix-CD6YHaHR.js → mock-matrix-Bkfl9ACG.js} +6 -2
- package/bundled-test-harness/assets/{mock-matrix-Dt4s2hUe.js → mock-matrix-DbxVPkSl.js} +1 -1
- package/bundled-test-harness/assets/{modal-container-wzIBYeE_.js → modal-container-BzEkpeIx.js} +1 -1
- package/bundled-test-harness/assets/{module-transpile-cache-test-Bj11UbQJ.js → module-transpile-cache-test-BFmN6_si.js} +1 -1
- package/bundled-test-harness/assets/{mp3-audio-def-test-C6tzxO6X.js → mp3-audio-def-test-DorbFtva.js} +1 -1
- package/bundled-test-harness/assets/{number-field-test-l5WRd3N9.js → number-field-test-C9F_sOf8.js} +2 -2
- package/bundled-test-harness/assets/{ogg-audio-def-test-CQ04xrfS.js → ogg-audio-def-test-DRXLSBVQ.js} +1 -1
- package/bundled-test-harness/assets/{on-key-CpWVcRaS.js → on-key-C8yMINOQ.js} +1 -1
- package/bundled-test-harness/assets/{open-create-listing-modal-test-VxITHH84.js → open-create-listing-modal-test-Yp6EOMGK.js} +1 -1
- package/bundled-test-harness/assets/open-image-in-new-tab-test-3iRCTOjd.js +52 -0
- package/bundled-test-harness/assets/{open-workspace-test-goAg_TVx.js → open-workspace-test-DrkNS6zm.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-acceptance-test-DO3lt95I.js → operator-mode-acceptance-test-DoQ5Klyi.js} +7 -7
- package/bundled-test-harness/assets/{operator-mode-card-catalog-test-C3e1--M7.js → operator-mode-card-catalog-test-Came_pKy.js} +4 -4
- package/bundled-test-harness/assets/{operator-mode-links-test-AWhMhHM2.js → operator-mode-links-test-DoTvJvpI.js} +4 -4
- package/bundled-test-harness/assets/{operator-mode-state-service-test-BICXMa5O.js → operator-mode-state-service-test-cwdudDwm.js} +2 -2
- package/bundled-test-harness/assets/{operator-mode-test-DMyFaXHK.js → operator-mode-test-DeUtV1XR.js} +4 -4
- package/bundled-test-harness/assets/{operator-mode-ui-test-z2SU5ozt.js → operator-mode-ui-test-DTUMZBlw.js} +4 -4
- package/bundled-test-harness/assets/{overlay-menu-items-test-Dkulmtpn.js → overlay-menu-items-test-DhPIUwmz.js} +3 -3
- package/bundled-test-harness/assets/{panel-BXXk_P7h.js → panel-DcMU_CGT.js} +55 -31
- package/bundled-test-harness/assets/{past-sessions-test-gKLwZO61.js → past-sessions-test-BrdqlYxe.js} +3 -3
- package/bundled-test-harness/assets/{patch-code-ClPL6B_d.js → patch-code-F_7JKtTQ.js} +1 -1
- package/bundled-test-harness/assets/{patch-code-test-CIdB45Nv.js → patch-code-test-O5_p8vp4.js} +4 -4
- package/bundled-test-harness/assets/{patch-fields-test-CBGnqUme.js → patch-fields-test-D1aSP1q_.js} +1 -1
- package/bundled-test-harness/assets/{patch-instance-test-DmDpfS3p.js → patch-instance-test-DHBeFzYI.js} +1 -1
- package/bundled-test-harness/assets/{persist-module-inspector-view-test-D6vpSfX4.js → persist-module-inspector-view-test-DDYttEKD.js} +2 -2
- package/bundled-test-harness/assets/{phone-number-field-test-DogtMkDx.js → phone-number-field-test-CUY1miSH.js} +2 -2
- package/bundled-test-harness/assets/{playground-CMnQXTzR.js → playground-DFwsIC-9.js} +2 -2
- package/bundled-test-harness/assets/{png-image-def-test-BzfrYGhY.js → png-image-def-test-C9COAyWm.js} +1 -1
- package/bundled-test-harness/assets/{prerender-file-extract-test-C-1R1B32.js → prerender-file-extract-test-B76NnPJt.js} +1 -1
- package/bundled-test-harness/assets/{prerender-html-test-1XGnbGuQ.js → prerender-html-test-ImXJjrpR.js} +1 -1
- package/bundled-test-harness/assets/{prerender-meta-test-B02oGS-5.js → prerender-meta-test-xIFFdF1X.js} +1 -1
- package/bundled-test-harness/assets/{prerender-module-test-CSKywVQA.js → prerender-module-test-CoxYOMro.js} +1 -1
- package/bundled-test-harness/assets/{prerendered-card-search-test-Cf_Hvr4P.js → prerendered-card-search-test-DLYUamOp.js} +2 -2
- package/bundled-test-harness/assets/{preview-format-Bb5FIkOY.js → preview-format-BqY_j3zZ.js} +1 -1
- package/bundled-test-harness/assets/{preview-format-test-DBKtwgvo.js → preview-format-test-CublqRWy.js} +4 -4
- package/bundled-test-harness/assets/{preview-test-dgbtaeLg.js → preview-test-CcGZEu6Y.js} +2 -2
- package/bundled-test-harness/assets/{publish-realm-test-B4c6TqTI.js → publish-realm-test-Cqq_X3L4.js} +2 -2
- package/bundled-test-harness/assets/{query-field-barrier-test-DytVxOcd.js → query-field-barrier-test-CeDBxTwq.js} +2 -2
- package/bundled-test-harness/assets/{query-field-error-sentinel-test-Cs2wXQuL.js → query-field-error-sentinel-test-CwOzGgRw.js} +2 -2
- package/bundled-test-harness/assets/{query-field-schema-test-ByfKD-mO.js → query-field-schema-test-CXt4ktVo.js} +1 -1
- package/bundled-test-harness/assets/{query-fields-test-SlJNtzM3.js → query-fields-test-CrsGkXWE.js} +1 -1
- package/bundled-test-harness/assets/{read-card-for-ai-assistant-test-BzThkf4s.js → read-card-for-ai-assistant-test-DORLxJXd.js} +2 -2
- package/bundled-test-harness/assets/{read-file-for-ai-assistant-test-CV5PoqSP.js → read-file-for-ai-assistant-test-DyyCSmMv.js} +2 -2
- package/bundled-test-harness/assets/{read-source-test-jfWyZkQO.js → read-source-test-hAUdteMO.js} +2 -2
- package/bundled-test-harness/assets/{read-text-file-test-Kg6tx07O.js → read-text-file-test-juQ-OJET.js} +2 -2
- package/bundled-test-harness/assets/{realm-oWsFVfdH.js → realm-CxU8jc8l.js} +2 -2
- package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-VyMT__jT.js → realm-config-routing-rule-edit-test-T8S_2Lwq.js} +47 -4
- package/bundled-test-harness/assets/{realm-field-test-CBmQY3Va.js → realm-field-test-wqNbmdgM.js} +2 -2
- package/bundled-test-harness/assets/{realm-indexing-test-CQ29IEno.js → realm-indexing-test-DTuwfnZZ.js} +1 -1
- package/bundled-test-harness/assets/{realm-querying-test-PR_91CCq.js → realm-querying-test-ojIOXC3n.js} +1 -1
- package/bundled-test-harness/assets/{realm-test-C6Kw7gWx.js → realm-test-MgXPmHwc.js} +1 -1
- package/bundled-test-harness/assets/{reasoning-test-M4JuH0RZ.js → reasoning-test-DcQkF04r.js} +3 -3
- package/bundled-test-harness/assets/{recent-files-cards-D845sggD.js → recent-files-cards-BICbCMhW.js} +1 -1
- package/bundled-test-harness/assets/{recent-files-test-Du5oiGDf.js → recent-files-test-Df_1aE3G.js} +2 -2
- package/bundled-test-harness/assets/{reindex-realm-test-BrgFBbOc.js → reindex-realm-test-DDYvNGWh.js} +2 -2
- package/bundled-test-harness/assets/{relationship-loading-state-test-CnCYYtmY.js → relationship-loading-state-test-C2EialRQ.js} +1 -1
- package/bundled-test-harness/assets/{render-component-BJwKMGDa.js → render-component-DLXpC-Bc.js} +1 -1
- package/bundled-test-harness/assets/{rendered-markdown-test-BvQ96-0V.js → rendered-markdown-test-DblOECt_.js} +2 -2
- package/bundled-test-harness/assets/{rich-markdown-field-test-neZFxfcc.js → rich-markdown-field-test-B34TJAq8.js} +2 -2
- package/bundled-test-harness/assets/{room-message-test-DWEcr5le.js → room-message-test-DuSkABnU.js} +3 -3
- package/bundled-test-harness/assets/{sanitize-module-list-test-B4VjLVx_.js → sanitize-module-list-test-BTFw8-Do.js} +2 -2
- package/bundled-test-harness/assets/{schema-editor-test-CHeST1JD.js → schema-editor-test-w7ANspy0.js} +1 -1
- package/bundled-test-harness/assets/{schema-generation-test-G4ZL90Sn.js → schema-generation-test-z90uBA7r.js} +3 -3
- package/bundled-test-harness/assets/{scrolling-test-D3Asc3Yr.js → scrolling-test-jCKormjp.js} +4 -4
- package/bundled-test-harness/assets/{search-and-choose-test-DMB-Nv1z.js → search-and-choose-test-BhIWdkFp.js} +2 -2
- package/bundled-test-harness/assets/{search-command-test-BNZzENdS.js → search-command-test-BlTBufTS.js} +1 -1
- package/bundled-test-harness/assets/{search-correlation-id-test-tM-SfbrA.js → search-correlation-id-test-BR7bFNCy.js} +1 -1
- package/bundled-test-harness/assets/{search-data-test-CYrjasBZ.js → search-data-test-bc2foKLa.js} +2 -2
- package/bundled-test-harness/assets/{search-google-images-test-DzFbLWZE.js → search-google-images-test-C96iDOxU.js} +1 -1
- package/bundled-test-harness/assets/{search-result-header-5VQHm_Ev.js → search-result-header-Ch7TKEzn.js} +1 -1
- package/bundled-test-harness/assets/{search-test-CBH8l5JD.js → search-test-iR0wammw.js} +2 -2
- package/bundled-test-harness/assets/{send-ai-assistant-message-test-CAlK3x0a.js → send-ai-assistant-message-test-BmJdWdzI.js} +2 -2
- package/bundled-test-harness/assets/{send-bot-trigger-event-test-CwI4Rkf8.js → send-bot-trigger-event-test-CJCAf2db.js} +2 -2
- package/bundled-test-harness/assets/{send-request-via-proxy-test-BRuk6sv0.js → send-request-via-proxy-test-DSdZppno.js} +2 -2
- package/bundled-test-harness/assets/{sending-test-BA2F7Hfk.js → sending-test-Bocu5vf9.js} +270 -12
- package/bundled-test-harness/assets/{serialization-test-DHTHfzsn.js → serialization-test-CE3TeQ4Z.js} +2 -2
- package/bundled-test-harness/assets/{set-user-system-card-test-Ct8xegEY.js → set-user-system-card-test-JZW2LcIA.js} +2 -2
- package/bundled-test-harness/assets/{setup-v4v1a2Qc.js → setup-C5QslpqI.js} +1 -1
- package/bundled-test-harness/assets/{setup-BfvQ1zfD.js → setup-CN-HHlT_.js} +2 -2
- package/bundled-test-harness/assets/{show-card-test-7VGIdTJh.js → show-card-test-B41I3EWZ.js} +3 -3
- package/bundled-test-harness/assets/{skills-test-NKDA1G9S.js → skills-test-Cut0gpNU.js} +3 -3
- package/bundled-test-harness/assets/{spec-test-61E0gdIB.js → spec-test-DytzFxZb.js} +3 -3
- package/bundled-test-harness/assets/{store-BM5pUF94.js → store-CbIxTljQ.js} +30 -0
- package/bundled-test-harness/assets/{store-add-test-mRtjroP0.js → store-add-test-ulvv9A3X.js} +2 -2
- package/bundled-test-harness/assets/{store-test-CVHw6LMN.js → store-test-C747NJ3O.js} +77 -4
- package/bundled-test-harness/assets/{submode-switcher-Popj4iN5.js → submode-switcher-iR4m0GzD.js} +1 -1
- package/bundled-test-harness/assets/{summarize-session-test-UZOGVM_F.js → summarize-session-test-BcXrj1r3.js} +2 -2
- package/bundled-test-harness/assets/{svg-image-def-test-Dqjy84jw.js → svg-image-def-test-DW1rtFSA.js} +1 -1
- package/bundled-test-harness/assets/{switch-submode-DOdRs5QD.js → switch-submode--ZVbWG3S.js} +1 -1
- package/bundled-test-harness/assets/{switch-submode-test-MWnyo759.js → switch-submode-test--Ncx8g_l.js} +3 -3
- package/bundled-test-harness/assets/{test-support-BfonQA4V.js → test-support-CCargU9V.js} +1 -1
- package/bundled-test-harness/assets/{tests-DQLSvmHe.js → tests-Dw_agY8k.js} +265 -263
- package/bundled-test-harness/assets/{text-file-def-test-DlyCDiM4.js → text-file-def-test-Bl2R6NO8.js} +1 -1
- package/bundled-test-harness/assets/{text-input-validator-test-Ccx-4gLo.js → text-input-validator-test-CAlDivoV.js} +3 -3
- package/bundled-test-harness/assets/{text-suggestion-test-mIvJOTS7.js → text-suggestion-test-CbJWk97Q.js} +1 -1
- package/bundled-test-harness/assets/{theme-card-test-Bs3Q034n.js → theme-card-test-Q5eP-lEF.js} +3 -3
- package/bundled-test-harness/assets/{transform-cards-test-BsTtRP0g.js → transform-cards-test-3PsuM2Sv.js} +2 -2
- package/bundled-test-harness/assets/{ts-file-def-test-DtWzgXkt.js → ts-file-def-test-BoXA3RgL.js} +1 -1
- package/bundled-test-harness/assets/{unpublish-realm-test-BFJEMQL7.js → unpublish-realm-test-CgiIcZ6j.js} +2 -2
- package/bundled-test-harness/assets/{update-room-skills-test-BrFhA3El.js → update-room-skills-test-B-BI7daL.js} +3 -3
- package/bundled-test-harness/assets/{use-ai-assistant-test-BsyBY6-a.js → use-ai-assistant-test-BEiEjFOH.js} +2 -2
- package/bundled-test-harness/assets/user-message-Bbw4pQmd.css +22 -0
- package/bundled-test-harness/assets/{user-message-BFN7dtqK.js → user-message-CVG3cgJq.js} +2 -2
- package/bundled-test-harness/assets/{validate-realm-test-DQlQ-pWZ.js → validate-realm-test-DBx-3YG9.js} +2 -2
- package/bundled-test-harness/assets/{wav-audio-def-test-BZ0oLTT1.js → wav-audio-def-test-CPJl6Hpr.js} +1 -1
- package/bundled-test-harness/assets/{webp-image-def-test-tuOTQeTt.js → webp-image-def-test-Bh3SOpDa.js} +1 -1
- package/bundled-test-harness/assets/{workspace-DvhB0Ltb.js → workspace-PBphyb9N.js} +2 -2
- package/bundled-test-harness/assets/{workspace-chooser-delete-test-D_Gp78-R.js → workspace-chooser-delete-test-1n1lqK_X.js} +3 -3
- package/bundled-test-harness/assets/{workspace-chooser-test-CuJ4pgJh.js → workspace-chooser-test-wcKYsTgx.js} +1 -1
- package/bundled-test-harness/assets/{workspace-delete-multiple-test-BUmKPHGp.js → workspace-delete-multiple-test-DlXWFVK1.js} +1 -1
- package/bundled-test-harness/assets/{workspace-delete-summary-test-B8qyNd7w.js → workspace-delete-summary-test-iqD1ae55.js} +1 -1
- package/bundled-test-harness/assets/{write-binary-file-test-D1h4TED_.js → write-binary-file-test-BkADCn85.js} +2 -2
- package/bundled-test-harness/assets/{write-text-file-test-DKA9TpIm.js → write-text-file-test-C9K0doTU.js} +2 -2
- package/bundled-test-harness/boxel-ui-checksum.txt +1 -1
- package/bundled-test-harness/index.html +33 -33
- package/bundled-test-harness/tests/index.html +36 -36
- package/bundled-types/base/field-component.d.ts +15 -4
- package/bundled-types/base/links-to-editor.d.ts +9 -0
- package/bundled-types/boxel-ui/components/filter-list/index.gts +4 -1
- package/bundled-types/host-app/components/ai-assistant/chat-input/index.gts +2 -1
- package/bundled-types/host-app/components/ai-assistant/message/user-message.gts +6 -2
- package/bundled-types/host-app/components/matrix/room.gts +115 -44
- package/bundled-types/host-app/lib/matrix-classes/message-builder.ts +13 -0
- package/bundled-types/host-app/services/local-persistence-service.ts +179 -0
- package/bundled-types/host-app/services/matrix-service.ts +372 -1
- package/bundled-types/host-app/services/store.ts +70 -0
- package/bundled-types/host-app/utils/local-storage-keys.ts +2 -0
- package/bundled-types/host-tests/helpers/mock-matrix/_client.ts +3 -0
- package/bundled-types/host-tests/helpers/mock-matrix/_utils.ts +3 -0
- package/bundled-types/host-tests/helpers/mock-matrix.ts +1 -0
- package/dist/index.js +257 -253
- package/package.json +3 -3
- package/src/commands/realm/index.ts +2 -0
- package/src/commands/realm/ingest-card.ts +567 -0
- package/src/commands/realm/publish.ts +87 -16
- package/src/commands/realm/pull.ts +9 -13
- package/src/commands/realm/push.ts +10 -14
- package/src/commands/realm/status.ts +14 -18
- package/src/commands/realm/sync.ts +9 -13
- package/src/commands/realm/unpublish.ts +11 -0
- package/src/lib/auth-resolver.ts +15 -2
- package/bundled-test-harness/assets/adapter-Dk9jvNQb.js +0 -2
- package/bundled-test-harness/assets/live-test-B7uB4aVp.js +0 -2
- package/bundled-test-harness/assets/user-message-B8olA3Ml.css +0 -18
- /package/bundled-test-harness/assets/{ai-assistant-panel-service-test-B2pqk_1r.js → ai-assistant-panel-service-test-DEeul-zv.js} +0 -0
- /package/bundled-test-harness/assets/{amd-transpile-test-ftXbwnFz.js → amd-transpile-test-DmEkMdCo.js} +0 -0
- /package/bundled-test-harness/assets/{apply-boxel-formatting-test-BSzr4sNI.js → apply-boxel-formatting-test-RixVcq5N.js} +0 -0
- /package/bundled-test-harness/assets/{auth-error-guard-test-BxIq12aN.js → auth-error-guard-test-beazl6s5.js} +0 -0
- /package/bundled-test-harness/assets/{bfm-card-references-test-6aAhfBzH.js → bfm-card-references-test-IEbg0jo-.js} +0 -0
- /package/bundled-test-harness/assets/{cached-fetch-test-CPr-eiq_.js → cached-fetch-test-DlnnpQGz.js} +0 -0
- /package/bundled-test-harness/assets/{card-directory-name-test-BS8WD3oH.js → card-directory-name-test-QKl1Ykz6.js} +0 -0
- /package/bundled-test-harness/assets/{card-search-query-builder-test-zp6muUB1.js → card-search-query-builder-test-BWc5lDv3.js} +0 -0
- /package/bundled-test-harness/assets/{code-patching-test-BZPvPsMr.js → code-patching-test-BRNMumI6.js} +0 -0
- /package/bundled-test-harness/assets/{code-semantics-service-test-BBjJ3EF3.js → code-semantics-service-test-CJOSUAQH.js} +0 -0
- /package/bundled-test-harness/assets/{command-definitions-test-BcMJzIBM.js → command-definitions-test-De0BMqHI.js} +0 -0
- /package/bundled-test-harness/assets/{extract-css-variables-test-FIZxFxaL.js → extract-css-variables-test-Di5CFXG-.js} +0 -0
- /package/bundled-test-harness/assets/{fetcher-test-g2cjjXxV.js → fetcher-test-Cb8cS9JN.js} +0 -0
- /package/bundled-test-harness/assets/{field-path-parser-test-DkY-DFQN.js → field-path-parser-test-Db4kG7EB.js} +0 -0
- /package/bundled-test-harness/assets/{file-def-manager-canonicalize-test-Dlf4HlLX.js → file-def-manager-canonicalize-test-Cq5B5KN4.js} +0 -0
- /package/bundled-test-harness/assets/{generate-css-variables-test-De4LPdBt.js → generate-css-variables-test-BahavIHR.js} +0 -0
- /package/bundled-test-harness/assets/{get-type-refs-from-filter-test-DmDF_dTY.js → get-type-refs-from-filter-test-CH5flf8B.js} +0 -0
- /package/bundled-test-harness/assets/{last-modified-date-test-C2hEJ3xU.js → last-modified-date-test-C_jV0b05.js} +0 -0
- /package/bundled-test-harness/assets/{limited-set-test-SLbA1cwS.js → limited-set-test-CcpIJCrn.js} +0 -0
- /package/bundled-test-harness/assets/{loader-icon-error-test-DTo5t1OQ.js → loader-icon-error-test-Bc_L-0Zb.js} +0 -0
- /package/bundled-test-harness/assets/{loader-retry-test-CPFmHSUN.js → loader-retry-test-DQ0E0a0N.js} +0 -0
- /package/bundled-test-harness/assets/{marked-sync-test-CaZYJo4x.js → marked-sync-test-JSqOc6hu.js} +0 -0
- /package/bundled-test-harness/assets/{mutex-test-p2qp1xRj.js → mutex-test-BDkeJutn.js} +0 -0
- /package/bundled-test-harness/assets/{plan-install-test-CrYUs1-G.js → plan-install-test-fUZIttPZ.js} +0 -0
- /package/bundled-test-harness/assets/{qs-test-DEH8SHFS.js → qs-test-CminVD53.js} +0 -0
- /package/bundled-test-harness/assets/{query-field-normalization-test-DrqBkUxD.js → query-field-normalization-test-B9alzE_u.js} +0 -0
- /package/bundled-test-harness/assets/{queue-test-CS3aOeHM.js → queue-test-BvWT6K7Z.js} +0 -0
- /package/bundled-test-harness/assets/{realm-index-card-id-test-FV_gOG_K.js → realm-index-card-id-test-hvCyEpGZ.js} +0 -0
- /package/bundled-test-harness/assets/{realm-paths-test-CvXB4BUZ.js → realm-paths-test-DrwpPXyh.js} +0 -0
- /package/bundled-test-harness/assets/{render-component-BabSF5nE.js → render-component-DY19erxA.js} +0 -0
- /package/bundled-test-harness/assets/{render-error-test-CvMDARjN.js → render-error-test-BC4QmstW.js} +0 -0
- /package/bundled-test-harness/assets/{render-service-test-DRCvv7lo.js → render-service-test-BkCkB3a2.js} +0 -0
- /package/bundled-test-harness/assets/{render-timer-stub-test-CVa_rjXp.js → render-timer-stub-test-cnMPidgA.js} +0 -0
- /package/bundled-test-harness/assets/{search-cache-key-test-r83Xl6Io.js → search-cache-key-test-DI0DKzU5.js} +0 -0
- /package/bundled-test-harness/assets/{search-in-flight-key-test-BmqFzX6o.js → search-in-flight-key-test-DyRDbEX1.js} +0 -0
- /package/bundled-test-harness/assets/{unified-search-results-test-D9v-CCog.js → unified-search-results-test-BF8Dps_j.js} +0 -0
- /package/bundled-test-harness/assets/{url-test-DtekKUme.js → url-test-DkEL_mbR.js} +0 -0
|
@@ -7,6 +7,7 @@ import type { SerializedFileDef } from 'https://cardstack.com/base/file-api';
|
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
AiAssistantMessageDrafts,
|
|
10
|
+
AiAssistantPendingSends,
|
|
10
11
|
CurrentRoomIdPersistenceKey,
|
|
11
12
|
} from '../utils/local-storage-keys';
|
|
12
13
|
|
|
@@ -30,6 +31,23 @@ type DraftUpdate = {
|
|
|
30
31
|
attachedFiles?: StoredFileDraft[] | undefined;
|
|
31
32
|
};
|
|
32
33
|
|
|
34
|
+
export type StoredPendingFile = Pick<
|
|
35
|
+
SerializedFileDef,
|
|
36
|
+
'sourceUrl' | 'name' | 'url' | 'contentType' | 'contentHash'
|
|
37
|
+
> & { contentSize?: number };
|
|
38
|
+
|
|
39
|
+
export type PendingSendStatus = 'sending' | 'not_sent';
|
|
40
|
+
|
|
41
|
+
export type StoredPendingSend = {
|
|
42
|
+
clientGeneratedId: string;
|
|
43
|
+
body: string;
|
|
44
|
+
attachedCardIds: string[];
|
|
45
|
+
attachedFiles: StoredPendingFile[];
|
|
46
|
+
createdAt: number;
|
|
47
|
+
status: PendingSendStatus;
|
|
48
|
+
errorMessage?: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
33
51
|
export default class LocalPersistenceService extends Service {
|
|
34
52
|
// Using sessionStorage for agent id because we want:
|
|
35
53
|
// - to keep the same agent id if user reloads the page (or tab)
|
|
@@ -287,6 +305,167 @@ export default class LocalPersistenceService extends Service {
|
|
|
287
305
|
let hasFiles = draft.attachedFiles && draft.attachedFiles.length > 0;
|
|
288
306
|
return !hasMessage && !hasCards && !hasFiles;
|
|
289
307
|
}
|
|
308
|
+
|
|
309
|
+
getPendingSends(roomId: string): StoredPendingSend[] {
|
|
310
|
+
return this.readPendingSends()[roomId] ?? [];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
upsertPendingSend(roomId: string, entry: StoredPendingSend) {
|
|
314
|
+
let all = this.readPendingSends();
|
|
315
|
+
let list = all[roomId] ? [...all[roomId]] : [];
|
|
316
|
+
let index = list.findIndex(
|
|
317
|
+
(e) => e.clientGeneratedId === entry.clientGeneratedId,
|
|
318
|
+
);
|
|
319
|
+
if (index >= 0) {
|
|
320
|
+
list[index] = entry;
|
|
321
|
+
} else {
|
|
322
|
+
list.push(entry);
|
|
323
|
+
}
|
|
324
|
+
all[roomId] = list;
|
|
325
|
+
this.writePendingSends(all);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
updatePendingSendStatus(
|
|
329
|
+
roomId: string,
|
|
330
|
+
clientGeneratedId: string,
|
|
331
|
+
update: { status: PendingSendStatus; errorMessage?: string },
|
|
332
|
+
) {
|
|
333
|
+
let all = this.readPendingSends();
|
|
334
|
+
let list = all[roomId];
|
|
335
|
+
if (!list) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
let index = list.findIndex(
|
|
339
|
+
(e) => e.clientGeneratedId === clientGeneratedId,
|
|
340
|
+
);
|
|
341
|
+
if (index < 0) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
let next = [...list];
|
|
345
|
+
next[index] = {
|
|
346
|
+
...next[index],
|
|
347
|
+
status: update.status,
|
|
348
|
+
errorMessage: update.errorMessage,
|
|
349
|
+
};
|
|
350
|
+
all[roomId] = next;
|
|
351
|
+
this.writePendingSends(all);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
removePendingSend(roomId: string, clientGeneratedId: string) {
|
|
355
|
+
let all = this.readPendingSends();
|
|
356
|
+
let list = all[roomId];
|
|
357
|
+
if (!list) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
let next = list.filter((e) => e.clientGeneratedId !== clientGeneratedId);
|
|
361
|
+
if (next.length === 0) {
|
|
362
|
+
delete all[roomId];
|
|
363
|
+
} else {
|
|
364
|
+
all[roomId] = next;
|
|
365
|
+
}
|
|
366
|
+
this.writePendingSends(all);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private readPendingSends(): Record<string, StoredPendingSend[]> {
|
|
370
|
+
let raw = window.localStorage.getItem(AiAssistantPendingSends);
|
|
371
|
+
if (!raw) {
|
|
372
|
+
return {};
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
let parsed = JSON.parse(raw);
|
|
376
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
377
|
+
return {};
|
|
378
|
+
}
|
|
379
|
+
let sanitized: Record<string, StoredPendingSend[]> = {};
|
|
380
|
+
for (let [roomId, list] of Object.entries(
|
|
381
|
+
parsed as Record<string, unknown>,
|
|
382
|
+
)) {
|
|
383
|
+
if (!Array.isArray(list)) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
let entries = list
|
|
387
|
+
.map((entry) => this.sanitizePendingSend(entry))
|
|
388
|
+
.filter((e): e is StoredPendingSend => Boolean(e));
|
|
389
|
+
if (entries.length > 0) {
|
|
390
|
+
sanitized[roomId] = entries;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return sanitized;
|
|
394
|
+
} catch {
|
|
395
|
+
window.localStorage.removeItem(AiAssistantPendingSends);
|
|
396
|
+
return {};
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private sanitizePendingSend(value: unknown): StoredPendingSend | undefined {
|
|
401
|
+
if (!value || typeof value !== 'object') {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
let cgi = (value as { clientGeneratedId?: unknown }).clientGeneratedId;
|
|
405
|
+
if (typeof cgi !== 'string' || cgi.length === 0) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
let body = (value as { body?: unknown }).body;
|
|
409
|
+
let attachedCardIds = (value as { attachedCardIds?: unknown })
|
|
410
|
+
.attachedCardIds;
|
|
411
|
+
let attachedFiles = (value as { attachedFiles?: unknown }).attachedFiles;
|
|
412
|
+
let createdAt = Number((value as { createdAt?: unknown }).createdAt);
|
|
413
|
+
let status = (value as { status?: unknown }).status;
|
|
414
|
+
let errorMessage = (value as { errorMessage?: unknown }).errorMessage;
|
|
415
|
+
|
|
416
|
+
return {
|
|
417
|
+
clientGeneratedId: cgi,
|
|
418
|
+
body: typeof body === 'string' ? body : '',
|
|
419
|
+
attachedCardIds: Array.isArray(attachedCardIds)
|
|
420
|
+
? attachedCardIds.filter(
|
|
421
|
+
(id): id is string => typeof id === 'string' && id.length > 0,
|
|
422
|
+
)
|
|
423
|
+
: [],
|
|
424
|
+
attachedFiles: Array.isArray(attachedFiles)
|
|
425
|
+
? (attachedFiles
|
|
426
|
+
.map((file) => this.sanitizePendingFile(file))
|
|
427
|
+
.filter(Boolean) as StoredPendingFile[])
|
|
428
|
+
: [],
|
|
429
|
+
createdAt: Number.isFinite(createdAt) ? createdAt : 0,
|
|
430
|
+
status: status === 'not_sent' ? 'not_sent' : 'sending',
|
|
431
|
+
errorMessage: typeof errorMessage === 'string' ? errorMessage : undefined,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private sanitizePendingFile(file: unknown): StoredPendingFile | undefined {
|
|
436
|
+
if (!file || typeof file !== 'object') {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
let sourceUrl = (file as { sourceUrl?: unknown }).sourceUrl;
|
|
440
|
+
if (typeof sourceUrl !== 'string' || sourceUrl.length === 0) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
let name = (file as { name?: unknown }).name;
|
|
444
|
+
let url = (file as { url?: unknown }).url;
|
|
445
|
+
let contentType = (file as { contentType?: unknown }).contentType;
|
|
446
|
+
let contentHash = (file as { contentHash?: unknown }).contentHash;
|
|
447
|
+
let contentSize = (file as { contentSize?: unknown }).contentSize;
|
|
448
|
+
return {
|
|
449
|
+
sourceUrl,
|
|
450
|
+
...(typeof name === 'string' ? { name } : {}),
|
|
451
|
+
...(typeof url === 'string' ? { url } : {}),
|
|
452
|
+
...(typeof contentType === 'string' ? { contentType } : {}),
|
|
453
|
+
...(typeof contentHash === 'string' ? { contentHash } : {}),
|
|
454
|
+
...(typeof contentSize === 'number' ? { contentSize } : {}),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private writePendingSends(all: Record<string, StoredPendingSend[]>) {
|
|
459
|
+
let entries = Object.entries(all).filter(([, list]) => list.length > 0);
|
|
460
|
+
if (entries.length === 0) {
|
|
461
|
+
window.localStorage.removeItem(AiAssistantPendingSends);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
window.localStorage.setItem(
|
|
465
|
+
AiAssistantPendingSends,
|
|
466
|
+
JSON.stringify(Object.fromEntries(entries)),
|
|
467
|
+
);
|
|
468
|
+
}
|
|
290
469
|
}
|
|
291
470
|
|
|
292
471
|
declare module '@ember/service' {
|
|
@@ -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 ||
|
|
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;
|