@cardstack/boxel-cli 0.13.0-unstable.4 → 0.13.0-unstable.5

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 (1050) hide show
  1. package/bundled-realms/pretui/components/doc-report.gts +2 -2
  2. package/bundled-realms/pretui/components/doc-report.usage.gts +3 -3
  3. package/bundled-realms/pretui/components/form-field.md +1 -1
  4. package/bundled-realms/pretui/components/icon-button.md +1 -1
  5. package/bundled-realms/pretui/components/popup.md +1 -1
  6. package/bundled-realms/pretui/components/switch.gts +13 -0
  7. package/bundled-realms/pretui/components/switch.md +5 -3
  8. package/bundled-realms/pretui/components/theme-frame.gts +49 -22
  9. package/bundled-realms/pretui/components/tooltip.gts +141 -42
  10. package/bundled-realms/pretui/components/tooltip.md +10 -12
  11. package/bundled-realms/pretui/components/tooltip.usage.gts +3 -5
  12. package/bundled-realms/pretui/docs/structure.md +1 -1
  13. package/bundled-realms/pretui/internal/overlay.gts +4 -2
  14. package/bundled-realms/pretui/pretui-css.gts +6 -2
  15. package/bundled-realms/pretui/theme-scoped-css.gts +262 -0
  16. package/bundled-test-harness/assets/account-switch-failed-test-DwAZq6Sc.js +45 -0
  17. package/bundled-test-harness/assets/adapter-C_6pnsx1.js +2 -0
  18. package/bundled-test-harness/assets/add-field-to-card-definition-tool-test-zMYtJWBv.js +112 -0
  19. package/bundled-test-harness/assets/ai-assistant-create-workspace-test-CwhAV-Ow.js +130 -0
  20. package/bundled-test-harness/assets/ai-assistant-panel-relogin-test-DNgclkGJ.js +46 -0
  21. package/bundled-test-harness/assets/ai-assistant-test-DGYFiRTb.js +2223 -0
  22. package/bundled-test-harness/assets/ai-function-generation-test-Dj6WzKkh.js +1176 -0
  23. package/bundled-test-harness/assets/ai-module-creation-test-EsOoJpQ1.js +151 -0
  24. package/bundled-test-harness/assets/aibot-message-uGaCPn5o.js +1312 -0
  25. package/bundled-test-harness/assets/app-pIzBYfiZ.js +14146 -0
  26. package/bundled-test-harness/assets/apply-markdown-edit-test-CPhfeg1i.js +230 -0
  27. package/bundled-test-harness/assets/ask-user-picker-NVRkhKwt.js +370 -0
  28. package/bundled-test-harness/assets/ask-user-picker-test-SsZqFm9W.js +39 -0
  29. package/bundled-test-harness/assets/assistant-transcript-test-DesuBCIB.js +57 -0
  30. package/bundled-test-harness/assets/audio-metadata-extractor-test-8JM6oZXG.js +1176 -0
  31. package/bundled-test-harness/assets/authed-fetch-test-yPTMe-9V.js +73 -0
  32. package/bundled-test-harness/assets/avif-image-def-test-Kyknj908.js +187 -0
  33. package/bundled-test-harness/assets/basic-test-D9OrrMaq.js +139 -0
  34. package/bundled-test-harness/assets/binary-upload-dedupe-test-Dnxlbbu6.js +308 -0
  35. package/bundled-test-harness/assets/bot-registration-test-Bk2lTaCW.js +97 -0
  36. package/bundled-test-harness/assets/box-test-BbV9sMyU.js +50 -0
  37. package/bundled-test-harness/assets/brand-guide-attachments-test-z4wTsKbI.js +84 -0
  38. package/bundled-test-harness/assets/brand-guide-custom-css-test-BlSJE8xo.js +196 -0
  39. package/bundled-test-harness/assets/brand-guide-edit-test-DJ1OQ6IB.js +140 -0
  40. package/bundled-test-harness/assets/brand-logo-mark-field-test-ux7eetkO.js +86 -0
  41. package/bundled-test-harness/assets/broken-link-template-test-CqB3MWyw.js +192 -0
  42. package/bundled-test-harness/assets/bundled-base-modules-test-B2oNLZSJ.js +54 -0
  43. package/bundled-test-harness/assets/bundled-base-oracle-test-DelPfFjn.js +37 -0
  44. package/bundled-test-harness/assets/buried-stack-item-scroll-test-Ixsl1tS0.js +236 -0
  45. package/bundled-test-harness/assets/button-BvYQm_A1.js +141 -0
  46. package/bundled-test-harness/assets/bxl-cyclic-graph-test-p23WCLRW.js +47 -0
  47. package/bundled-test-harness/assets/bxl-expression-test-CVTQYT_C.js +250 -0
  48. package/bundled-test-harness/assets/bxl-indexing-test-D_A7X2sr.js +212 -0
  49. package/bundled-test-harness/assets/bxl-platform-module-test-Cltfyybp.js +71 -0
  50. package/bundled-test-harness/assets/can-invoke-test-DJi7jMaU.js +455 -0
  51. package/bundled-test-harness/assets/can-read-realm-test-CIz6WX_K.js +56 -0
  52. package/bundled-test-harness/assets/cancel-indexing-job-test-0LlrOgYK.js +69 -0
  53. package/bundled-test-harness/assets/capture-test-diHIWmh0.js +360 -0
  54. package/bundled-test-harness/assets/card-api-test-Ci9b0ghP.js +198 -0
  55. package/bundled-test-harness/assets/card-basics-test-RKQoQWZD.js +5364 -0
  56. package/bundled-test-harness/assets/card-chooser-paging-test-BoUyFMEw.js +235 -0
  57. package/bundled-test-harness/assets/card-chooser-test-7ZwhxxkH.js +393 -0
  58. package/bundled-test-harness/assets/card-context-search-results-KmkXJbmC.js +30 -0
  59. package/bundled-test-harness/assets/card-context-search-results-test-CpMr8OlX.js +184 -0
  60. package/bundled-test-harness/assets/card-def-field-def-relationships-test-ByPl5n55.js +562 -0
  61. package/bundled-test-harness/assets/card-def-menu-items-test-ohuHc0b4.js +228 -0
  62. package/bundled-test-harness/assets/card-delete-test-Be971b-V.js +466 -0
  63. package/bundled-test-harness/assets/card-error-3q1o3i0e.js +72 -0
  64. package/bundled-test-harness/assets/card-error-awaiting-index-test-DPgYKfbF.js +53 -0
  65. package/bundled-test-harness/assets/card-info-thumbnail-picker-test-CVfeJyjt.js +219 -0
  66. package/bundled-test-harness/assets/card-playground-test-D-7bi4PQ.js +1491 -0
  67. package/bundled-test-harness/assets/card-prerender-DemTfK_a.js +12939 -0
  68. package/bundled-test-harness/assets/card-thunk-error-test-DCBh1vRT.js +48 -0
  69. package/bundled-test-harness/assets/card-type-service-test-DXPrfVYk.js +161 -0
  70. package/bundled-test-harness/assets/check-correctness-test-DjE7r1X2.js +1093 -0
  71. package/bundled-test-harness/assets/check-domain-availability-test-U10xSKbY.js +98 -0
  72. package/bundled-test-harness/assets/chip-0r_r9SC8.js +44 -0
  73. package/bundled-test-harness/assets/choreo-Ci5dG5fv.js +2 -0
  74. package/bundled-test-harness/assets/choreo-D1K9RyjM.js +1031 -0
  75. package/bundled-test-harness/assets/choreo-feature-reel-test-vzmW-SFd.js +155 -0
  76. package/bundled-test-harness/assets/choreo-gallery-build-order-test-J6n0_PKm.js +436 -0
  77. package/bundled-test-harness/assets/choreo-gallery-compositor-test-DSi1N9bi.js +399 -0
  78. package/bundled-test-harness/assets/choreo-gallery-cover-test-BT05gNKC.js +214 -0
  79. package/bundled-test-harness/assets/choreo-gallery-crossing-stage-test-BIuLOZH6.js +133 -0
  80. package/bundled-test-harness/assets/choreo-gallery-demos-alive-test-ClGjpnj6.js +42 -0
  81. package/bundled-test-harness/assets/choreo-gallery-drift-test-OjxMXV0Y.js +620 -0
  82. package/bundled-test-harness/assets/choreo-gallery-escort-test-D6VL4FfT.js +187 -0
  83. package/bundled-test-harness/assets/choreo-gallery-films-test-DBcDHGx8.js +140 -0
  84. package/bundled-test-harness/assets/choreo-gallery-filter-test-BUghtJZe.js +46 -0
  85. package/bundled-test-harness/assets/choreo-gallery-fold-test-0D9-_h_I.js +180 -0
  86. package/bundled-test-harness/assets/choreo-gallery-guide-pages-test-DS41eNNV.js +114 -0
  87. package/bundled-test-harness/assets/choreo-gallery-guides-test-CZnaxUNJ.js +321 -0
  88. package/bundled-test-harness/assets/choreo-gallery-hang-test-WFvsJ-MJ.js +426 -0
  89. package/bundled-test-harness/assets/choreo-gallery-highlight-test-Dn0hYPLC.js +60 -0
  90. package/bundled-test-harness/assets/choreo-gallery-inline-edit-test-C5WvS67s.js +370 -0
  91. package/bundled-test-harness/assets/choreo-gallery-interruption-test-CgT9RKTe.js +176 -0
  92. package/bundled-test-harness/assets/choreo-gallery-lone-stack-test-BZgqbTJd.js +104 -0
  93. package/bundled-test-harness/assets/choreo-gallery-navigation-test-CWzXkvbW.js +193 -0
  94. package/bundled-test-harness/assets/choreo-gallery-playhead-transport-test-Dt71t4CU.js +111 -0
  95. package/bundled-test-harness/assets/choreo-gallery-poplayout-subtree-test-B_rDq4em.js +127 -0
  96. package/bundled-test-harness/assets/choreo-gallery-presence-modes-test-j_cZ9cAM.js +100 -0
  97. package/bundled-test-harness/assets/choreo-gallery-presentation-test-CIFKR65J.js +157 -0
  98. package/bundled-test-harness/assets/choreo-gallery-reduced-motion-test-BvRCiCvB.js +145 -0
  99. package/bundled-test-harness/assets/choreo-gallery-sheet-standalone-test-DgO2MBzU.js +89 -0
  100. package/bundled-test-harness/assets/choreo-gallery-sheet-test-BntUKT_P.js +48 -0
  101. package/bundled-test-harness/assets/choreo-gallery-site-test-CvSE6Jyq.js +237 -0
  102. package/bundled-test-harness/assets/choreo-gallery-stage-Dj6tFzon.js +256 -0
  103. package/bundled-test-harness/assets/choreo-gallery-stage-keyboard-test-CkDrAPA8.js +102 -0
  104. package/bundled-test-harness/assets/choreo-gallery-stages-test-DHUmzoRW.js +35 -0
  105. package/bundled-test-harness/assets/choreo-gallery-subdivision-test-BZ9-cDFh.js +138 -0
  106. package/bundled-test-harness/assets/choreo-gallery-table-plan-test-7uP6mZpo.js +144 -0
  107. package/bundled-test-harness/assets/choreo-gallery-theater-test-DgEue9FD.js +252 -0
  108. package/bundled-test-harness/assets/choreo-gallery-tuning-test-CfPx5iCp.js +95 -0
  109. package/bundled-test-harness/assets/choreo-gallery-widget-room-test-o9T2EFKq.js +88 -0
  110. package/bundled-test-harness/assets/choreo-gallery-wires-test-73JLkxn6.js +148 -0
  111. package/bundled-test-harness/assets/client-telemetry-test-DFM4mML2.js +340 -0
  112. package/bundled-test-harness/assets/clip-CsRtHZiN.js +92 -0
  113. package/bundled-test-harness/assets/clip-CycGr0Lf.js +2 -0
  114. package/bundled-test-harness/assets/code-block-DRE8KQZQ.js +502 -0
  115. package/bundled-test-harness/assets/code-ref-test-CDcqE8_C.js +163 -0
  116. package/bundled-test-harness/assets/code-submode-availability-test-DPTqZYYm.js +198 -0
  117. package/bundled-test-harness/assets/code-submode-test-AHV4mzJ4.js +1839 -0
  118. package/bundled-test-harness/assets/codeblocks-test-D9pbJMK8.js +418 -0
  119. package/bundled-test-harness/assets/codemirror-editor-test-BeAMVivu.js +1512 -0
  120. package/bundled-test-harness/assets/codemirror-embed-toolbar-test-Bnb7_KUT.js +366 -0
  121. package/bundled-test-harness/assets/color-field-test-CR6gGEqE.js +212 -0
  122. package/bundled-test-harness/assets/compaction-test-BSqAGv4g.js +150 -0
  123. package/bundled-test-harness/assets/computed-test-DtyZGgdc.js +1320 -0
  124. package/bundled-test-harness/assets/container-CEslVSTe.js +10884 -0
  125. package/bundled-test-harness/assets/content-preview-components-test-BztI4fz-.js +462 -0
  126. package/bundled-test-harness/assets/copy-and-edit-test-Cqw7kcur.js +292 -0
  127. package/bundled-test-harness/assets/copy-card-test-D5m3eVEH.js +218 -0
  128. package/bundled-test-harness/assets/copy-file-to-realm-test-FPY-6Ddm.js +148 -0
  129. package/bundled-test-harness/assets/copy-source-test-9pJD-qey.js +56 -0
  130. package/bundled-test-harness/assets/create-file-test-DjMf88u_.js +1086 -0
  131. package/bundled-test-harness/assets/create-file-test-XbgOqg38.js +464 -0
  132. package/bundled-test-harness/assets/create-listing-modal-test-DyGlGMWu.js +273 -0
  133. package/bundled-test-harness/assets/create-listing-pr-request-test-CBtIV0Z8.js +117 -0
  134. package/bundled-test-harness/assets/create-spec-test-4xR0gM7E.js +256 -0
  135. package/bundled-test-harness/assets/create-submission-workflow-test-DQpWrpGT.js +132 -0
  136. package/bundled-test-harness/assets/create-workspace-test-BQAudgpS.js +104 -0
  137. package/bundled-test-harness/assets/credential-fields-test-DXKBdbZD.js +200 -0
  138. package/bundled-test-harness/assets/csv-file-def-test-Cnp4y834.js +102 -0
  139. package/bundled-test-harness/assets/dashboard-CmuOhIYC.js +3628 -0
  140. package/bundled-test-harness/assets/dashboard-CzN49x74.css +2400 -0
  141. package/bundled-test-harness/assets/dashboard-add-workspace-test-T32hWB-g.js +50 -0
  142. package/bundled-test-harness/assets/dashboard-agents-test-BN5maCgQ.js +334 -0
  143. package/bundled-test-harness/assets/dashboard-archive-test-BzwUte_Z.js +128 -0
  144. package/bundled-test-harness/assets/dashboard-delete-test-D2Gcp81V.js +163 -0
  145. package/bundled-test-harness/assets/dashboard-duplicate-offer-test-BgKNIr35.js +71 -0
  146. package/bundled-test-harness/assets/dashboard-duplicate-test-D7JEWylc.js +222 -0
  147. package/bundled-test-harness/assets/dashboard-get-started-test-DOGPzGoA.js +374 -0
  148. package/bundled-test-harness/assets/dashboard-ir2bakJS.js +142 -0
  149. package/bundled-test-harness/assets/dashboard-pinned-cards-test-Bn_P9xJU.js +220 -0
  150. package/bundled-test-harness/assets/dashboard-publish-test-64sGQ0nG.js +70 -0
  151. package/bundled-test-harness/assets/dashboard-reindex-test-DJjYq1ct.js +115 -0
  152. package/bundled-test-harness/assets/dashboard-section-rail-test-ZkAhWu5V.js +169 -0
  153. package/bundled-test-harness/assets/dashboard-state-test-BbkpPB5L.js +162 -0
  154. package/bundled-test-harness/assets/dashboard-test-CBLdPrSt.js +545 -0
  155. package/bundled-test-harness/assets/dashboard-unreachable-notice-test-DFT3R1Zx.js +62 -0
  156. package/bundled-test-harness/assets/dashboard-workspace-test-DqBdCFo2.js +537 -0
  157. package/bundled-test-harness/assets/dashboard-workspaces-section-test-CH1HDfxR.js +410 -0
  158. package/bundled-test-harness/assets/data-file-def-preview-test-CNsZwQEJ.js +155 -0
  159. package/bundled-test-harness/assets/date-time-fields-test-CEFaZTnF.js +359 -0
  160. package/bundled-test-harness/assets/debug-message-test-0hv0RwE_.js +117 -0
  161. package/bundled-test-harness/assets/declared-captures-test-C-0yPRU7.js +879 -0
  162. package/bundled-test-harness/assets/delete-workspace-test-CZOwGy78.js +102 -0
  163. package/bundled-test-harness/assets/diffing-test-BEKI905O.js +210 -0
  164. package/bundled-test-harness/assets/download-file-to-realm-test-C1kAGDll.js +119 -0
  165. package/bundled-test-harness/assets/editor-test-C9x5ZY6g.js +688 -0
  166. package/bundled-test-harness/assets/edits-D76-aanh.js +651 -0
  167. package/bundled-test-harness/assets/email-field-test-LGkrB_2B.js +75 -0
  168. package/bundled-test-harness/assets/enum-field-test-CPyV1J-m.js +935 -0
  169. package/bundled-test-harness/assets/error-display-test-bWuUtfIG.js +343 -0
  170. package/bundled-test-harness/assets/evaluate-module-test-CbS5h8t3.js +91 -0
  171. package/bundled-test-harness/assets/execute-atomic-operations-test-B4Kfco0k.js +113 -0
  172. package/bundled-test-harness/assets/externals-CDQm-Lm7.js +4393 -0
  173. package/bundled-test-harness/assets/fallback-banner-live-delete-test-DQSiTzvj.js +207 -0
  174. package/bundled-test-harness/assets/fallback-banner-test-CJFKLpOy.js +225 -0
  175. package/bundled-test-harness/assets/fallback-banner-test-DQkrFE4-.js +53 -0
  176. package/bundled-test-harness/assets/fallback-models-test-CiWfmxaB.js +161 -0
  177. package/bundled-test-harness/assets/fetch-card-json-test-DULUqUEu.js +61 -0
  178. package/bundled-test-harness/assets/field-configuration-test-BXZq28xa.js +551 -0
  179. package/bundled-test-harness/assets/field-markdown-domain-test-DdXCifs6.js +616 -0
  180. package/bundled-test-harness/assets/field-markdown-oversize-test-DouPPTHX.js +88 -0
  181. package/bundled-test-harness/assets/field-markdown-primitives-test-DSRGJeyl.js +365 -0
  182. package/bundled-test-harness/assets/field-markdown-specialized-test-DlTYLl_s.js +534 -0
  183. package/bundled-test-harness/assets/field-playground-test-NhS4VvoN.js +894 -0
  184. package/bundled-test-harness/assets/field-support-predicates-test-DWpyT1Qf.js +167 -0
  185. package/bundled-test-harness/assets/file-attachment-test-m72-VerW.js +796 -0
  186. package/bundled-test-harness/assets/file-chooser-panel-test-DuAqD9bn.js +153 -0
  187. package/bundled-test-harness/assets/file-chooser-test-CjaXXwpT.js +504 -0
  188. package/bundled-test-harness/assets/file-def-format-templates-test-BDs4OmHq.js +380 -0
  189. package/bundled-test-harness/assets/file-def-live-reload-test-BqTdnq-W.js +124 -0
  190. package/bundled-test-harness/assets/file-def-menu-items-test-DqdINXsD.js +138 -0
  191. package/bundled-test-harness/assets/file-def-navigation-test-BPGr0SQy.js +109 -0
  192. package/bundled-test-harness/assets/file-def-serialization-test-CvjW-FlC.js +89 -0
  193. package/bundled-test-harness/assets/file-def-test-C-Yv_NjS.js +216 -0
  194. package/bundled-test-harness/assets/file-preview-live-reload-test-MzwGwasU.js +310 -0
  195. package/bundled-test-harness/assets/file-resource-primitives-test-D3GmfqNs.js +255 -0
  196. package/bundled-test-harness/assets/file-tree-from-index-test-CfldnUgm.js +96 -0
  197. package/bundled-test-harness/assets/file-tree-test--0ZCPRe9.js +851 -0
  198. package/bundled-test-harness/assets/file-view-model-test-BDIAeBV8.js +346 -0
  199. package/bundled-test-harness/assets/filedef-export-shape-test-B2tgU404.js +61 -0
  200. package/bundled-test-harness/assets/film-D1E-odYG.js +13 -0
  201. package/bundled-test-harness/assets/film-D25Y0ED6.js +2 -0
  202. package/bundled-test-harness/assets/film-D97U-ydx.js +4074 -0
  203. package/bundled-test-harness/assets/flac-audio-def-test-ByoXMoQ1.js +143 -0
  204. package/bundled-test-harness/assets/font-metadata-extractor-test-hawLTDTG.js +415 -0
  205. package/bundled-test-harness/assets/formatted-aibot-message-test-Bdx_-Ktn.js +109 -0
  206. package/bundled-test-harness/assets/formatted-user-message-test-CodbrU3t.js +43 -0
  207. package/bundled-test-harness/assets/freestyle-test-faQhSciz.js +17 -0
  208. package/bundled-test-harness/assets/full-reindex-realm-test-CE5RJTIC.js +101 -0
  209. package/bundled-test-harness/assets/garbage-collection-test-v-3sev77.js +403 -0
  210. package/bundled-test-harness/assets/general-test-DQuxDvXK.js +923 -0
  211. package/bundled-test-harness/assets/generate-example-cards-one-shot-test-CucWyrkH.js +65 -0
  212. package/bundled-test-harness/assets/generic-file-def-preview-test-_EDRsebi.js +71 -0
  213. package/bundled-test-harness/assets/get-available-realm-identifiers-test-CV023yek.js +47 -0
  214. package/bundled-test-harness/assets/get-catalog-realm-identifiers-test--DOu3DyV.js +47 -0
  215. package/bundled-test-harness/assets/get-default-writable-realm-test-Bic8jl6R.js +54 -0
  216. package/bundled-test-harness/assets/get-published-realms-test-DrA5YcFN.js +71 -0
  217. package/bundled-test-harness/assets/get-realm-of-resource-identifier-test-jfU6SIWn.js +54 -0
  218. package/bundled-test-harness/assets/get-relationship-membership-state-test-Ccy2Z7MN.js +1308 -0
  219. package/bundled-test-harness/assets/get-user-system-card-test-Bmq2lmWv.js +67 -0
  220. package/bundled-test-harness/assets/gif-image-def-test-N1mMQC-X.js +188 -0
  221. package/bundled-test-harness/assets/glimmer-motion-and-choreo-in-cards-test-DzPKH76g.js +160 -0
  222. package/bundled-test-harness/assets/glimmer-motion-and-choreo-test-D9mlcQuN.js +74 -0
  223. package/bundled-test-harness/assets/gts-file-def-test-BL1jpQ9J.js +100 -0
  224. package/bundled-test-harness/assets/head-format-preview-test-BVCaPQqc.js +158 -0
  225. package/bundled-test-harness/assets/helpers-Ds68JxHe.js +5 -0
  226. package/bundled-test-harness/assets/host-mode-service-B4bisRdR.js +262 -0
  227. package/bundled-test-harness/assets/host-mode-test-BmkN2PCJ.js +831 -0
  228. package/bundled-test-harness/assets/host-submode-test-C6SxQ796.js +1392 -0
  229. package/bundled-test-harness/assets/html-component-test-CNQ9wF0Q.js +65 -0
  230. package/bundled-test-harness/assets/html-def-test-BcaCVVQq.js +160 -0
  231. package/bundled-test-harness/assets/html-meta-extractor-test-BU1hjkTp.js +60 -0
  232. package/bundled-test-harness/assets/hydratable-card-test-CX6MWiti.js +426 -0
  233. package/bundled-test-harness/assets/icon-button-C1zH38Nc.js +67 -0
  234. package/bundled-test-harness/assets/image-metadata-extractor-test-CakSBPZ_.js +1109 -0
  235. package/bundled-test-harness/assets/index-changes-test-D8RtgfyG.js +367 -0
  236. package/bundled-test-harness/assets/index-query-engine-test-BOvxkx07.js +2593 -0
  237. package/bundled-test-harness/assets/index-writer-test-B_bR2fjw.js +3040 -0
  238. package/bundled-test-harness/assets/inspector-test-BwPXJj1S.js +2058 -0
  239. package/bundled-test-harness/assets/instance-filter-matcher-test-COAlkUed.js +788 -0
  240. package/bundled-test-harness/assets/instantiate-card-test-BVQhZjpq.js +164 -0
  241. package/bundled-test-harness/assets/interact-submode-creation-and-permissions-test-DzQLG41H.js +475 -0
  242. package/bundled-test-harness/assets/interact-submode-setup-C5bKXq73.js +566 -0
  243. package/bundled-test-harness/assets/invalidate-realm-identifiers-test-Cd3dpjhB.js +99 -0
  244. package/bundled-test-harness/assets/invite-user-to-room-test-Brabz1tt.js +142 -0
  245. package/bundled-test-harness/assets/invoke-card-operation-test-C1Q1FUf4.js +333 -0
  246. package/bundled-test-harness/assets/isolated-render-test-BLJfS7BU.js +51 -0
  247. package/bundled-test-harness/assets/job-scoped-doc-cache-test-Bgv5woaB.js +181 -0
  248. package/bundled-test-harness/assets/job-scoped-instance-residency-test-C_bB6KpR.js +103 -0
  249. package/bundled-test-harness/assets/jpg-image-def-test-gdLIKocD.js +697 -0
  250. package/bundled-test-harness/assets/json-file-def-test-CPYMRBY-.js +95 -0
  251. package/bundled-test-harness/assets/key-notices-badge-test-DemslfLw.js +155 -0
  252. package/bundled-test-harness/assets/key-readiness-test-5tq5JycL.js +190 -0
  253. package/bundled-test-harness/assets/linksto-broken-link-placeholder-test-BbhDZ2PH.js +398 -0
  254. package/bundled-test-harness/assets/linksto-error-sentinel-test-C2t7fFPi.js +238 -0
  255. package/bundled-test-harness/assets/linksto-many-broken-link-placeholder-test--U_UvUty.js +354 -0
  256. package/bundled-test-harness/assets/linksto-many-per-slot-access-test-Dj3Xy0ZF.js +303 -0
  257. package/bundled-test-harness/assets/linksto-sentinel-reload-test-D0dK4Jjs.js +197 -0
  258. package/bundled-test-harness/assets/linksto-sentinel-roundtrip-test---IYiXok.js +260 -0
  259. package/bundled-test-harness/assets/linksto-singular-js-access-contract-test-CT04MhES.js +196 -0
  260. package/bundled-test-harness/assets/lint-and-fix-test-aadgx7rX.js +51 -0
  261. package/bundled-test-harness/assets/live-test-BGij_vuc.js +100 -0
  262. package/bundled-test-harness/assets/live-test-CppvValf.js +2 -0
  263. package/bundled-test-harness/assets/load-default-skills-test-Cp2m_ebp.js +74 -0
  264. package/bundled-test-harness/assets/loader-parallel-prefetch-test-vU_26Jqu.js +257 -0
  265. package/bundled-test-harness/assets/loader-test-CTaw8K_B.js +482 -0
  266. package/bundled-test-harness/assets/loading-test-DGGt4qZZ.js +63 -0
  267. package/bundled-test-harness/assets/m4a-audio-def-test-DAiReOXH.js +190 -0
  268. package/bundled-test-harness/assets/main-DUKPWRts.js +5 -0
  269. package/bundled-test-harness/assets/markdown-embed-chooser-modal-test-CIXq9FqR.js +470 -0
  270. package/bundled-test-harness/assets/markdown-embed-chooser-test-zFGh9WfP.js +334 -0
  271. package/bundled-test-harness/assets/markdown-embed-preview-pane-test-Byn_WFwY.js +447 -0
  272. package/bundled-test-harness/assets/markdown-embed-preview-test-Y3iFMttg.js +368 -0
  273. package/bundled-test-harness/assets/markdown-fallback-test-Br1TPkLZ.js +316 -0
  274. package/bundled-test-harness/assets/markdown-file-def-test-Crm2MAnq.js +380 -0
  275. package/bundled-test-harness/assets/markdown-helpers-test-CZ9Vvywc.js +188 -0
  276. package/bundled-test-harness/assets/markdown-highlighting-test-CFMkoVDl.js +244 -0
  277. package/bundled-test-harness/assets/markdown-preview-Df5fp1SY.js +72 -0
  278. package/bundled-test-harness/assets/markdown-preview-test-DDaPzsVs.js +238 -0
  279. package/bundled-test-harness/assets/markdown-skill-frontmatter-test-aH6HQly1.js +146 -0
  280. package/bundled-test-harness/assets/markdown-skill-search-test-CiNLQs-5.js +80 -0
  281. package/bundled-test-harness/assets/matrix-service-account-switch-sessions-test-DaA8w1Jj.js +63 -0
  282. package/bundled-test-harness/assets/matrix-service-boot-assembly-test-21GIlf55.js +300 -0
  283. package/bundled-test-harness/assets/matrix-service-personal-realm-test-jn9DUENm.js +125 -0
  284. package/bundled-test-harness/assets/matrix-service-realm-servers-test-eNZVJakl.js +55 -0
  285. package/bundled-test-harness/assets/matrix-service-realms-list-updated-test-Cabm8_dY.js +132 -0
  286. package/bundled-test-harness/assets/matrix-service-relogin-test-C77EFgjc.js +59 -0
  287. package/bundled-test-harness/assets/matrix-service-sliding-sync-test-BgM0fPiO.js +35 -0
  288. package/bundled-test-harness/assets/menu-Cl50TSFe.js +3561 -0
  289. package/bundled-test-harness/assets/message-service-subscription-test-CfEqH2jP.js +110 -0
  290. package/bundled-test-harness/assets/message-service-test-DsTzH1In.js +144 -0
  291. package/bundled-test-harness/assets/message-tool-test-C5xVfTtj.js +33 -0
  292. package/bundled-test-harness/assets/midi-audio-def-test-goLRCNCZ.js +182 -0
  293. package/bundled-test-harness/assets/migrate-skill-test-yPCbVfxG.js +161 -0
  294. package/bundled-test-harness/assets/mini-YXjrY_tH.js +1404 -0
  295. package/bundled-test-harness/assets/mini-card-chooser-test-DrllikHB.js +272 -0
  296. package/bundled-test-harness/assets/mini-file-chooser-test-BfqayhmI.js +201 -0
  297. package/bundled-test-harness/assets/mock-matrix-C7BrPS6S.js +2 -0
  298. package/bundled-test-harness/assets/mock-matrix-FjsXmU7-.js +15107 -0
  299. package/bundled-test-harness/assets/modal-BgaZavcs.js +322 -0
  300. package/bundled-test-harness/assets/model-cost-tier-test-CZlu1zww.js +174 -0
  301. package/bundled-test-harness/assets/model-file-extract-test-CjEBupY5.js +206 -0
  302. package/bundled-test-harness/assets/module-transpile-cache-test-XW6DDsmz.js +67 -0
  303. package/bundled-test-harness/assets/monaco-test-DkoRuFiQ.js +100 -0
  304. package/bundled-test-harness/assets/mp3-audio-def-test-v369NNsQ.js +133 -0
  305. package/bundled-test-harness/assets/multiple-stacks-test-CJpYPWdM.js +208 -0
  306. package/bundled-test-harness/assets/nested-query-field-render-test-CfDrBcUN.js +249 -0
  307. package/bundled-test-harness/assets/no-stacks-test-MmsJeLpz.js +48 -0
  308. package/bundled-test-harness/assets/number-field-test-A7B2r0M5.js +184 -0
  309. package/bundled-test-harness/assets/office-file-def-test-BNRvFmCB.js +263 -0
  310. package/bundled-test-harness/assets/office-metadata-extractor-test-zlDoEIEp.js +218 -0
  311. package/bundled-test-harness/assets/office-poster-capture-test-DdFEaOxR.js +203 -0
  312. package/bundled-test-harness/assets/ogg-audio-def-test-kk91BzQY.js +196 -0
  313. package/bundled-test-harness/assets/open-create-listing-modal-test-D1Dl1pov.js +131 -0
  314. package/bundled-test-harness/assets/open-image-in-new-tab-test-DyCmdMyO.js +52 -0
  315. package/bundled-test-harness/assets/open-secure-window-test-dz1vPudF.js +253 -0
  316. package/bundled-test-harness/assets/open-workspace-test-BvTcskzP.js +46 -0
  317. package/bundled-test-harness/assets/operation-lowering-test-CKkamOQt.js +2957 -0
  318. package/bundled-test-harness/assets/operations-invocation-test-BMj42rQe.js +523 -0
  319. package/bundled-test-harness/assets/operations-optimistic-test-KJLyzT8v.js +203 -0
  320. package/bundled-test-harness/assets/operations-query-test-J3HcnaoK.js +459 -0
  321. package/bundled-test-harness/assets/operations-store-reconciliation-test-CkbGBMBQ.js +406 -0
  322. package/bundled-test-harness/assets/operations-test-C7zXXpRW.js +2518 -0
  323. package/bundled-test-harness/assets/operator-mode-acceptance-test-BPolI_RD.js +1195 -0
  324. package/bundled-test-harness/assets/operator-mode-card-chooser-test-CQ1v8med.js +1036 -0
  325. package/bundled-test-harness/assets/operator-mode-links-test-BMHEauS3.js +797 -0
  326. package/bundled-test-harness/assets/operator-mode-test-blL_JVF8.js +696 -0
  327. package/bundled-test-harness/assets/operator-mode-ui-test-BG6I7-Hc.js +1045 -0
  328. package/bundled-test-harness/assets/overlay-D2rQi8lJ.js +427 -0
  329. package/bundled-test-harness/assets/overlay-menu-items-test-D-zmRQQ0.js +331 -0
  330. package/bundled-test-harness/assets/overlays-COinwHCP.js +2 -0
  331. package/bundled-test-harness/assets/overlays-detached-element-test-C73nMXes.js +56 -0
  332. package/bundled-test-harness/assets/overlays-nTqcu69K.js +75 -0
  333. package/bundled-test-harness/assets/panel-D9SEMehG.js +15124 -0
  334. package/bundled-test-harness/assets/past-sessions-test-De9N4wVX.js +321 -0
  335. package/bundled-test-harness/assets/patch-fields-test-Bp2IE0Jw.js +1014 -0
  336. package/bundled-test-harness/assets/patch-instance-test-DssuRGKP.js +348 -0
  337. package/bundled-test-harness/assets/pdf-file-def-test-Barj9ffD.js +111 -0
  338. package/bundled-test-harness/assets/pdf-metadata-extractor-test-B7KnXcIm.js +130 -0
  339. package/bundled-test-harness/assets/permission-checking-realm-test-OBzvhDB_.js +306 -0
  340. package/bundled-test-harness/assets/persist-module-inspector-view-test-BIdbkdPr.js +60 -0
  341. package/bundled-test-harness/assets/persist-scroll-position-test-Bhb7wJiy.js +254 -0
  342. package/bundled-test-harness/assets/phone-number-field-test-C2yuCrXY.js +73 -0
  343. package/bundled-test-harness/assets/pill-menu-test-BIp91YXi.js +60 -0
  344. package/bundled-test-harness/assets/plate-DAr_pvwC.js +41 -0
  345. package/bundled-test-harness/assets/plate-DeoQd99m.js +2 -0
  346. package/bundled-test-harness/assets/player-BvXGBItd.js +2 -0
  347. package/bundled-test-harness/assets/player-CAVQUyKk.js +82 -0
  348. package/bundled-test-harness/assets/playground-B02e8uqB.js +58 -0
  349. package/bundled-test-harness/assets/plural-field-components-test-C1acuN-A.js +198 -0
  350. package/bundled-test-harness/assets/png-image-def-test-B9QeVo1f.js +266 -0
  351. package/bundled-test-harness/assets/policy-audit-confirmation-test-CeVquvc_.js +155 -0
  352. package/bundled-test-harness/assets/policy-scoped-search-test-SFPiIqR3.js +339 -0
  353. package/bundled-test-harness/assets/prerender-file-extract-test-HSJKAHyO.js +346 -0
  354. package/bundled-test-harness/assets/prerender-html-test-BTAcFCme.js +670 -0
  355. package/bundled-test-harness/assets/prerender-meta-test-Csyz2b21.js +614 -0
  356. package/bundled-test-harness/assets/prerender-module-test-DpTYAbmI.js +409 -0
  357. package/bundled-test-harness/assets/prerender-persistence-block-test-BhIt-7kK.js +124 -0
  358. package/bundled-test-harness/assets/prerender-pre-model-error-test-DxKPQKqx.js +61 -0
  359. package/bundled-test-harness/assets/prerender-serialize-cycle-test-C8V5YWQO.js +134 -0
  360. package/bundled-test-harness/assets/prerendered-html-read-test-Cq7JVGwg.js +191 -0
  361. package/bundled-test-harness/assets/pretui-components-test-Ducr9fLT.css +743 -0
  362. package/bundled-test-harness/assets/pretui-components-test-Hs0uyIUQ.js +992 -0
  363. package/bundled-test-harness/assets/pretui-primitives-CRs8NRm0.js +69 -0
  364. package/bundled-test-harness/assets/preview-format-test-cCqLrfdY.js +103 -0
  365. package/bundled-test-harness/assets/preview-test-BMqJSoR1.js +474 -0
  366. package/bundled-test-harness/assets/process-card-test-578tfDvr.js +94 -0
  367. package/bundled-test-harness/assets/profile-settings-modal-CVnNl7Yu.js +990 -0
  368. package/bundled-test-harness/assets/publish-realm-COoeWexp.js +82 -0
  369. package/bundled-test-harness/assets/publish-realm-test-a5nkx0Ov.js +210 -0
  370. package/bundled-test-harness/assets/query-field-barrier-test-qX3xVPfk.js +113 -0
  371. package/bundled-test-harness/assets/query-field-error-sentinel-test-V6JDPFLX.js +201 -0
  372. package/bundled-test-harness/assets/query-field-membership-status-test-CK7eDf-K.js +323 -0
  373. package/bundled-test-harness/assets/query-field-page-optin-test-B5YBHUvU.js +126 -0
  374. package/bundled-test-harness/assets/query-field-schema-test-D4SjOGlK.js +231 -0
  375. package/bundled-test-harness/assets/query-field-search-throttle-test-BVkm1-D8.js +154 -0
  376. package/bundled-test-harness/assets/query-field-stale-prerender-test-9g7hcD91.js +152 -0
  377. package/bundled-test-harness/assets/query-fields-test-CQYqhzpN.js +535 -0
  378. package/bundled-test-harness/assets/quick-look-test-icQwb1NJ.js +139 -0
  379. package/bundled-test-harness/assets/read-card-for-ai-assistant-test-D0mJorwH.js +91 -0
  380. package/bundled-test-harness/assets/read-file-for-ai-assistant-test-B_F_2GEB.js +45 -0
  381. package/bundled-test-harness/assets/read-source-test-BgJV4B4F.js +67 -0
  382. package/bundled-test-harness/assets/read-text-file-test-DaeLzg4u.js +124 -0
  383. package/bundled-test-harness/assets/realm-C_a9su1j.js +2858 -0
  384. package/bundled-test-harness/assets/realm-api-keys-D5USFOoS.js +2 -0
  385. package/bundled-test-harness/assets/realm-api-keys-m_VOcixC.js +578 -0
  386. package/bundled-test-harness/assets/realm-api-keys-test-C_uZnTmq.js +588 -0
  387. package/bundled-test-harness/assets/realm-api-keys-test-gtJ8XZCE.js +109 -0
  388. package/bundled-test-harness/assets/realm-config-m5eccPW8.js +833 -0
  389. package/bundled-test-harness/assets/realm-config-policy-standing-test-CXJ4ZMde.js +290 -0
  390. package/bundled-test-harness/assets/realm-config-routing-rule-edit-test-DoEunShH.js +274 -0
  391. package/bundled-test-harness/assets/realm-config-settings-test-BYi9i4O6.js +187 -0
  392. package/bundled-test-harness/assets/realm-field-test-B_PUoqnk.js +100 -0
  393. package/bundled-test-harness/assets/realm-indexing-test-8iLjeV_e.js +4380 -0
  394. package/bundled-test-harness/assets/realm-policy-fitted-test-Bptvra0U.js +206 -0
  395. package/bundled-test-harness/assets/realm-policy-test-DwG0qqXE.js +1141 -0
  396. package/bundled-test-harness/assets/realm-querying-test-Dvw26A6Q.js +1067 -0
  397. package/bundled-test-harness/assets/realm-server-form-agnostic-test-DrXQH0UP.js +96 -0
  398. package/bundled-test-harness/assets/realm-server-subscriber-test-Dkj23vQK.js +46 -0
  399. package/bundled-test-harness/assets/realm-service-info-test-CdRlDhj-.js +67 -0
  400. package/bundled-test-harness/assets/realm-test-DGYN48Qx.js +2364 -0
  401. package/bundled-test-harness/assets/realm-token-refresh-test-CEWATL9h.js +153 -0
  402. package/bundled-test-harness/assets/realm-url-tooltip-test-8ZjTNPuy.js +78 -0
  403. package/bundled-test-harness/assets/reasoning-test-WUx-4agu.js +221 -0
  404. package/bundled-test-harness/assets/recent-files-test-Dc6L6Dm4.js +450 -0
  405. package/bundled-test-harness/assets/reindex-realm-test-CFRSt39u.js +117 -0
  406. package/bundled-test-harness/assets/relationship-loading-state-test-FKbtOFUr.js +290 -0
  407. package/bundled-test-harness/assets/remix-card-test-CKGC_Sgq.js +58 -0
  408. package/bundled-test-harness/assets/rendered-markdown-B_jWmDrK.js +292 -0
  409. package/bundled-test-harness/assets/rendered-markdown-test-sdWhU0NA.js +587 -0
  410. package/bundled-test-harness/assets/resident-instance-reuse-test-BjdhE6CM.js +82 -0
  411. package/bundled-test-harness/assets/result-tile-o6dtjgX4.js +144 -0
  412. package/bundled-test-harness/assets/rich-markdown-field-test-VXr6l20h.js +1647 -0
  413. package/bundled-test-harness/assets/room-message-test-BYNhZ39n.js +484 -0
  414. package/bundled-test-harness/assets/run-FzaqmBEl.js +3959 -0
  415. package/bundled-test-harness/assets/run-realm-code-DsBUf1si.js +2964 -0
  416. package/bundled-test-harness/assets/run-realm-code-test-cS0DzaKo.js +3844 -0
  417. package/bundled-test-harness/assets/sanitize-module-list-test-CvuOOiUY.js +85 -0
  418. package/bundled-test-harness/assets/save-card-skip-index-wait-test-fpJ1eq32.js +89 -0
  419. package/bundled-test-harness/assets/schema-editor-test-NkKjCgyf.js +785 -0
  420. package/bundled-test-harness/assets/schema-generation-test-Dmg3lWl7.js +28 -0
  421. package/bundled-test-harness/assets/scrolling-test-Dd4gv_fj.js +412 -0
  422. package/bundled-test-harness/assets/search-adorn-test-CZebk7_y.js +136 -0
  423. package/bundled-test-harness/assets/search-and-choose-test-Bd4NZUup.js +154 -0
  424. package/bundled-test-harness/assets/search-correlation-id-test-DXKlEO55.js +139 -0
  425. package/bundled-test-harness/assets/search-entries-result-test-QQawA8Fm.js +234 -0
  426. package/bundled-test-harness/assets/search-entries-test-3DlqGPQq.js +1486 -0
  427. package/bundled-test-harness/assets/search-entries-tool-test-D1TvDE9D.js +504 -0
  428. package/bundled-test-harness/assets/search-google-images-test-DqsoQGr1.js +166 -0
  429. package/bundled-test-harness/assets/search-results-DGrNaPxh.js +266 -0
  430. package/bundled-test-harness/assets/search-results-test-CqVHYNRt.js +578 -0
  431. package/bundled-test-harness/assets/search-selection-menu-test-D6bIjKiH.js +108 -0
  432. package/bundled-test-harness/assets/search-sheet-files-test-Bf37TQXo.js +126 -0
  433. package/bundled-test-harness/assets/search-sheet-persistence-test-CV4_XdxR.js +131 -0
  434. package/bundled-test-harness/assets/search-test-Dlb-wg3a.js +2249 -0
  435. package/bundled-test-harness/assets/search-tool-test-BJLgVMoL.js +156 -0
  436. package/bundled-test-harness/assets/searchable-option-test-eJaIPH_L.js +322 -0
  437. package/bundled-test-harness/assets/searchable-search-doc-test-yH9fLGNS.js +1271 -0
  438. package/bundled-test-harness/assets/section-rail-CNFCebtT.js +113 -0
  439. package/bundled-test-harness/assets/section-rail-test-KNJAWWl6.js +256 -0
  440. package/bundled-test-harness/assets/secure-sign-in-Dyljp0Th.js +174 -0
  441. package/bundled-test-harness/assets/secure-sign-in-test-QnqNuTP3.js +373 -0
  442. package/bundled-test-harness/assets/segmented-control-DxJdoJ4Z.js +173 -0
  443. package/bundled-test-harness/assets/select-BiQTg2ts.js +175 -0
  444. package/bundled-test-harness/assets/send-ai-assistant-message-test-CAn7M2dZ.js +52 -0
  445. package/bundled-test-harness/assets/send-bot-trigger-event-test-qBu5E_jy.js +56 -0
  446. package/bundled-test-harness/assets/send-request-via-proxy-test-CLuwLBq_.js +380 -0
  447. package/bundled-test-harness/assets/sending-test-Dt9Dh2wW.js +659 -0
  448. package/bundled-test-harness/assets/serialization-rri-form-audit-test-hMJukiKt.js +136 -0
  449. package/bundled-test-harness/assets/serialization-test-W5e3wKbz.js +8758 -0
  450. package/bundled-test-harness/assets/set-user-system-card-test-CjgWLkNV.js +59 -0
  451. package/bundled-test-harness/assets/setup-CssMNvui.js +772 -0
  452. package/bundled-test-harness/assets/setup-D8YXvK-p.js +2 -0
  453. package/bundled-test-harness/assets/shared-link-target-reuse-test-D42UO8DC.js +207 -0
  454. package/bundled-test-harness/assets/show-card-test-CHEaS514.js +365 -0
  455. package/bundled-test-harness/assets/signed-capture-link-test-BgEu0F-S.js +132 -0
  456. package/bundled-test-harness/assets/single-stack-test-DYcu_v7Z.js +652 -0
  457. package/bundled-test-harness/assets/skills-test-BP8QNesE.js +648 -0
  458. package/bundled-test-harness/assets/skip-boot-index-guard-test-BzRIncDN.js +46 -0
  459. package/bundled-test-harness/assets/spec-test-BYvFR6Xb.js +1077 -0
  460. package/bundled-test-harness/assets/spinner-Bx9x55NA.js +49 -0
  461. package/bundled-test-harness/assets/src-LqENIikj.js +5 -0
  462. package/bundled-test-harness/assets/src-a4d10Hra.js +216 -0
  463. package/bundled-test-harness/assets/stick-to-bottom-resize-test-BBLiCR3X.js +56 -0
  464. package/bundled-test-harness/assets/store-add-test-D_9IHQjZ.js +50 -0
  465. package/bundled-test-harness/assets/store-module-rebuild-test-BRGZoLRV.js +454 -0
  466. package/bundled-test-harness/assets/store-search-test-3G8JHuj2.js +175 -0
  467. package/bundled-test-harness/assets/store-test-Dd4WQp7L.js +3672 -0
  468. package/bundled-test-harness/assets/structured-theme-test-11TNsgUW.js +377 -0
  469. package/bundled-test-harness/assets/summarize-session-test-CwzD_ZbD.js +172 -0
  470. package/bundled-test-harness/assets/svg-image-def-test-zV6aMK9q.js +167 -0
  471. package/bundled-test-harness/assets/switch-submode-test-DQU2cP5_.js +168 -0
  472. package/bundled-test-harness/assets/sync-openrouter-models-test-xrXVaC2H.js +97 -0
  473. package/bundled-test-harness/assets/test-support-QTh6wGxu.js +3 -0
  474. package/bundled-test-harness/assets/test-support-Tr-PYFgc.js +99 -0
  475. package/bundled-test-harness/assets/tests-zLlwPutr.js +3598 -0
  476. package/bundled-test-harness/assets/text-file-def-test-Cyq78UFY.js +94 -0
  477. package/bundled-test-harness/assets/text-input-validator-test-C1uDVZU7.js +156 -0
  478. package/bundled-test-harness/assets/text-suggestion-test-C4XAqWqY.js +340 -0
  479. package/bundled-test-harness/assets/theme-card-test-dVNz4tgU.js +621 -0
  480. package/bundled-test-harness/assets/theme-dashboard-nav-test-DYSn5pqo.js +196 -0
  481. package/bundled-test-harness/assets/theme-scheme-island-test-C1WpkfEP.js +264 -0
  482. package/bundled-test-harness/assets/theme-scoped-css-parity-test-BVluppsE.js +176 -0
  483. package/bundled-test-harness/assets/titles-0a1luoTq.js +52 -0
  484. package/bundled-test-harness/assets/titles-DKHNLVwC.js +2 -0
  485. package/bundled-test-harness/assets/to-device-streaming-test-3A6jI0_r.js +163 -0
  486. package/bundled-test-harness/assets/token-usage-test-33ovcqPk.js +160 -0
  487. package/bundled-test-harness/assets/tools-J_Knr_W6.js +774 -0
  488. package/bundled-test-harness/assets/tools-calling-test-CfqZX0Ed.js +200 -0
  489. package/bundled-test-harness/assets/tools-test-B4x58ZmI.js +1624 -0
  490. package/bundled-test-harness/assets/tools-test-DtUQp5ez.js +3204 -0
  491. package/bundled-test-harness/assets/tooltip-B0rEgyMW.css +66 -0
  492. package/bundled-test-harness/assets/tooltip-DvUMUgVX.js +195 -0
  493. package/bundled-test-harness/assets/transform-cards-test-CYQbZeD9.js +341 -0
  494. package/bundled-test-harness/assets/ts-file-def-preview-test-m39f8Zio.js +95 -0
  495. package/bundled-test-harness/assets/ts-file-def-test-xIcL5xWe.js +92 -0
  496. package/bundled-test-harness/assets/ttf-font-def-test-ClQ2SzFF.js +206 -0
  497. package/bundled-test-harness/assets/turn-settling-test-DqYk312r.js +160 -0
  498. package/bundled-test-harness/assets/turn-summary-Bmt7ZxTS.js +1039 -0
  499. package/bundled-test-harness/assets/unpublish-realm-test-0ToTJczx.js +102 -0
  500. package/bundled-test-harness/assets/update-room-skills-test-o_j8NOUV.js +240 -0
  501. package/bundled-test-harness/assets/use-ai-assistant-test-D7HFpxKJ.js +384 -0
  502. package/bundled-test-harness/assets/user-message-BAOt1hS3.js +262 -0
  503. package/bundled-test-harness/assets/validate-realm-test-e3xIbNLB.js +67 -0
  504. package/bundled-test-harness/assets/video-metadata-extractor-test-D8naLSlg.js +520 -0
  505. package/bundled-test-harness/assets/view-visually-test-BuhGau5E.js +335 -0
  506. package/bundled-test-harness/assets/virtual-network-reset-test-CgaFNGPi.js +96 -0
  507. package/bundled-test-harness/assets/wav-audio-def-test-CWG_UdCh.js +160 -0
  508. package/bundled-test-harness/assets/webp-image-def-test-sN4yw8Zu.js +226 -0
  509. package/bundled-test-harness/assets/workspace-0LfPqbYB.js +445 -0
  510. package/bundled-test-harness/assets/workspace-a11y-test-DQxYDRAP.js +197 -0
  511. package/bundled-test-harness/assets/workspace-actions-jGJSfl8M.js +588 -0
  512. package/bundled-test-harness/assets/workspace-behavior-test-BnF-bmBN.js +338 -0
  513. package/bundled-test-harness/assets/workspace-delete-multiple-test-D-rxPDuT.js +212 -0
  514. package/bundled-test-harness/assets/workspace-delete-summary-test-C2-Mve5R.js +63 -0
  515. package/bundled-test-harness/assets/workspace-hosting-test-BvDKdlOb.js +138 -0
  516. package/bundled-test-harness/assets/workspace-indexing-test-B34T3kqD.js +71 -0
  517. package/bundled-test-harness/assets/workspace-test-CJivgv-m.js +51 -0
  518. package/bundled-test-harness/assets/workspace-test-CuSRpPnQ.js +385 -0
  519. package/bundled-test-harness/assets/workspace-timestamp-labels-test-aWgjdbCp.js +68 -0
  520. package/bundled-test-harness/assets/workspace-unit-test-DHMUf2KT.js +122 -0
  521. package/bundled-test-harness/assets/write-binary-file-test-P-hVQuin.js +124 -0
  522. package/bundled-test-harness/assets/write-text-file-test-fXvJueDd.js +191 -0
  523. package/bundled-test-harness/assets/zip-archive-test-C2P5CUSR.js +285 -0
  524. package/bundled-test-harness/assets/zip-file-def-test-BfJZAmGt.js +164 -0
  525. package/bundled-test-harness/boxel-ui-checksum.txt +1 -1
  526. package/bundled-test-harness/index.html +47 -47
  527. package/bundled-test-harness/tests/index.html +49 -49
  528. package/bundled-types/boxel-ui/helpers/theme-scoped-css.ts +4 -0
  529. package/bundled-types/choreo/choreo.gts +13 -1
  530. package/bundled-types/choreo/run.ts +19 -0
  531. package/bundled-types/host-app/components/operator-mode/dashboard/get-started.gts +152 -7
  532. package/bundled-types/host-app/components/operator-mode/dashboard/index.gts +2 -0
  533. package/bundled-types/host-app/components/operator-mode/dashboard/workspace.gts +5 -3
  534. package/bundled-types/host-app/components/operator-mode/dashboard-modals/workspace-modals.gts +5 -22
  535. package/bundled-types/host-app/components/operator-mode/host-submode/publishing-realm-popover.gts +1 -1
  536. package/bundled-types/host-app/components/operator-mode/host-submode.gts +111 -37
  537. package/bundled-types/host-app/components/operator-mode/publish-realm-modal.gts +1 -0
  538. package/bundled-types/host-app/lib/modal-focus-trap.ts +33 -0
  539. package/bundled-types/host-app/lib/workspace-actions.ts +21 -0
  540. package/bundled-types/host-app/services/host-mode-service.ts +39 -0
  541. package/bundled-types/host-app/services/realm.ts +14 -0
  542. package/bundled-types/host-tests/helpers/dashboard.ts +67 -0
  543. package/package.json +1 -1
  544. package/bundled-test-harness/assets/account-switch-failed-test-FytUFiPO.js +0 -45
  545. package/bundled-test-harness/assets/adapter-DvmPwSZv.js +0 -2
  546. package/bundled-test-harness/assets/add-field-to-card-definition-tool-test-DN525jiY.js +0 -112
  547. package/bundled-test-harness/assets/ai-assistant-create-workspace-test-q3tKqVJQ.js +0 -130
  548. package/bundled-test-harness/assets/ai-assistant-panel-relogin-test-DgeXcCyi.js +0 -46
  549. package/bundled-test-harness/assets/ai-assistant-test-lDIGPKFP.js +0 -2223
  550. package/bundled-test-harness/assets/ai-function-generation-test-D5GbLyvL.js +0 -1176
  551. package/bundled-test-harness/assets/ai-module-creation-test-I3-j2beD.js +0 -151
  552. package/bundled-test-harness/assets/aibot-message-Dmsjifs6.js +0 -1312
  553. package/bundled-test-harness/assets/app-BS9_-DhN.js +0 -14146
  554. package/bundled-test-harness/assets/apply-markdown-edit-test-4zlwt0Db.js +0 -230
  555. package/bundled-test-harness/assets/ask-user-picker-Dr-0qpNr.js +0 -370
  556. package/bundled-test-harness/assets/ask-user-picker-test-633AFdmS.js +0 -39
  557. package/bundled-test-harness/assets/assistant-transcript-test-BgRnLvMg.js +0 -57
  558. package/bundled-test-harness/assets/audio-metadata-extractor-test-4xsQqL-0.js +0 -1176
  559. package/bundled-test-harness/assets/authed-fetch-test-663mT5_N.js +0 -73
  560. package/bundled-test-harness/assets/avif-image-def-test-h01BPIJy.js +0 -187
  561. package/bundled-test-harness/assets/basic-test-DiD6T-8Q.js +0 -139
  562. package/bundled-test-harness/assets/binary-upload-dedupe-test-CkjMPO_e.js +0 -308
  563. package/bundled-test-harness/assets/bot-registration-test-CFZHpwdj.js +0 -97
  564. package/bundled-test-harness/assets/box-test-C3pSy5ED.js +0 -50
  565. package/bundled-test-harness/assets/brand-guide-attachments-test-EoC_u7Vc.js +0 -84
  566. package/bundled-test-harness/assets/brand-guide-custom-css-test-Dn3fvblr.js +0 -196
  567. package/bundled-test-harness/assets/brand-guide-edit-test-NeiT3MyK.js +0 -140
  568. package/bundled-test-harness/assets/brand-logo-mark-field-test-C2A1EnBB.js +0 -86
  569. package/bundled-test-harness/assets/broken-link-template-test-CWn6V5zZ.js +0 -192
  570. package/bundled-test-harness/assets/bundled-base-modules-test-D7mLzpsw.js +0 -54
  571. package/bundled-test-harness/assets/bundled-base-oracle-test-I7xCId_k.js +0 -37
  572. package/bundled-test-harness/assets/buried-stack-item-scroll-test-DFBev0h-.js +0 -236
  573. package/bundled-test-harness/assets/button-BeSuhveJ.js +0 -207
  574. package/bundled-test-harness/assets/bxl-cyclic-graph-test-DPykwvvx.js +0 -47
  575. package/bundled-test-harness/assets/bxl-expression-test-LBWJiFb9.js +0 -250
  576. package/bundled-test-harness/assets/bxl-indexing-test-BuZmLk7y.js +0 -212
  577. package/bundled-test-harness/assets/bxl-platform-module-test-BNIvlkCM.js +0 -71
  578. package/bundled-test-harness/assets/can-invoke-test-t-bFIIeX.js +0 -455
  579. package/bundled-test-harness/assets/can-read-realm-test-2Q_MzRT9.js +0 -56
  580. package/bundled-test-harness/assets/cancel-indexing-job-test-QeYxEukn.js +0 -69
  581. package/bundled-test-harness/assets/capture-test-CJmJG8YR.js +0 -360
  582. package/bundled-test-harness/assets/card-api-test-B43I510H.js +0 -198
  583. package/bundled-test-harness/assets/card-basics-test-CBClzP2y.js +0 -5364
  584. package/bundled-test-harness/assets/card-chooser-paging-test-HEVzf6pR.js +0 -235
  585. package/bundled-test-harness/assets/card-chooser-test-GfjBRPFI.js +0 -393
  586. package/bundled-test-harness/assets/card-context-search-results-CoSr4EdS.js +0 -30
  587. package/bundled-test-harness/assets/card-context-search-results-test-BLMlZu9t.js +0 -184
  588. package/bundled-test-harness/assets/card-def-field-def-relationships-test-DEBOzKan.js +0 -562
  589. package/bundled-test-harness/assets/card-def-menu-items-test-88_h8o0D.js +0 -228
  590. package/bundled-test-harness/assets/card-delete-test-DKom1phy.js +0 -466
  591. package/bundled-test-harness/assets/card-error-awaiting-index-test-DEwgFZMP.js +0 -53
  592. package/bundled-test-harness/assets/card-error-r6_cXst9.js +0 -72
  593. package/bundled-test-harness/assets/card-info-thumbnail-picker-test-B7LiY15e.js +0 -219
  594. package/bundled-test-harness/assets/card-playground-test-CgyIJHui.js +0 -1491
  595. package/bundled-test-harness/assets/card-prerender-rPfzpIOU.js +0 -12939
  596. package/bundled-test-harness/assets/card-thunk-error-test-L0pvg4Ce.js +0 -48
  597. package/bundled-test-harness/assets/card-type-service-test-B2dhqxSD.js +0 -161
  598. package/bundled-test-harness/assets/check-correctness-test-DgqaLlCW.js +0 -1093
  599. package/bundled-test-harness/assets/check-domain-availability-test-B0hJHY5l.js +0 -98
  600. package/bundled-test-harness/assets/chip-D01NW3WH.js +0 -44
  601. package/bundled-test-harness/assets/choreo-D2Jl79RU.js +0 -1019
  602. package/bundled-test-harness/assets/choreo-_E8SOEe-.js +0 -2
  603. package/bundled-test-harness/assets/choreo-feature-reel-test-WLjsZDmS.js +0 -155
  604. package/bundled-test-harness/assets/choreo-gallery-build-order-test-6jnS8PsS.js +0 -436
  605. package/bundled-test-harness/assets/choreo-gallery-compositor-test-CbUZsVB6.js +0 -399
  606. package/bundled-test-harness/assets/choreo-gallery-cover-test-CbvAStgk.js +0 -214
  607. package/bundled-test-harness/assets/choreo-gallery-crossing-stage-test-tdjvUSa6.js +0 -133
  608. package/bundled-test-harness/assets/choreo-gallery-demos-alive-test-CsnM3hQK.js +0 -42
  609. package/bundled-test-harness/assets/choreo-gallery-drift-test-DG2LQTa7.js +0 -620
  610. package/bundled-test-harness/assets/choreo-gallery-escort-test-mn3-qXP1.js +0 -187
  611. package/bundled-test-harness/assets/choreo-gallery-films-test-BuktaC0D.js +0 -140
  612. package/bundled-test-harness/assets/choreo-gallery-filter-test-Dd-zpps0.js +0 -46
  613. package/bundled-test-harness/assets/choreo-gallery-fold-test-CWc1ijGc.js +0 -180
  614. package/bundled-test-harness/assets/choreo-gallery-guide-pages-test-tk2QmYPU.js +0 -114
  615. package/bundled-test-harness/assets/choreo-gallery-guides-test-DVbf1zM4.js +0 -321
  616. package/bundled-test-harness/assets/choreo-gallery-hang-test-B7EFp2dx.js +0 -426
  617. package/bundled-test-harness/assets/choreo-gallery-highlight-test-BFgbdesP.js +0 -60
  618. package/bundled-test-harness/assets/choreo-gallery-inline-edit-test-DJb8FC5R.js +0 -370
  619. package/bundled-test-harness/assets/choreo-gallery-interruption-test-DWyMXo5D.js +0 -176
  620. package/bundled-test-harness/assets/choreo-gallery-lone-stack-test-D3b8LsJ6.js +0 -104
  621. package/bundled-test-harness/assets/choreo-gallery-navigation-test-CjjU6Rvn.js +0 -193
  622. package/bundled-test-harness/assets/choreo-gallery-playhead-transport-test-Le_h3QWU.js +0 -111
  623. package/bundled-test-harness/assets/choreo-gallery-poplayout-subtree-test-Cp-DlWj4.js +0 -127
  624. package/bundled-test-harness/assets/choreo-gallery-presence-modes-test-DayS4GCJ.js +0 -100
  625. package/bundled-test-harness/assets/choreo-gallery-presentation-test-DeAfuFS7.js +0 -157
  626. package/bundled-test-harness/assets/choreo-gallery-reduced-motion-test-BgPWpggq.js +0 -145
  627. package/bundled-test-harness/assets/choreo-gallery-sheet-standalone-test-PzyoMNYv.js +0 -89
  628. package/bundled-test-harness/assets/choreo-gallery-sheet-test-CxaiNBkL.js +0 -48
  629. package/bundled-test-harness/assets/choreo-gallery-site-test-6xtSntS5.js +0 -237
  630. package/bundled-test-harness/assets/choreo-gallery-stage-E6Q5r-zU.js +0 -256
  631. package/bundled-test-harness/assets/choreo-gallery-stage-keyboard-test-C7aWMr9a.js +0 -102
  632. package/bundled-test-harness/assets/choreo-gallery-stages-test-CDWWgC61.js +0 -35
  633. package/bundled-test-harness/assets/choreo-gallery-subdivision-test-Bkp15XJv.js +0 -138
  634. package/bundled-test-harness/assets/choreo-gallery-table-plan-test-CcGRi_3O.js +0 -144
  635. package/bundled-test-harness/assets/choreo-gallery-theater-test-Qph5pLT_.js +0 -252
  636. package/bundled-test-harness/assets/choreo-gallery-tuning-test-C4DhFLVA.js +0 -95
  637. package/bundled-test-harness/assets/choreo-gallery-widget-room-test-LK493r1M.js +0 -88
  638. package/bundled-test-harness/assets/choreo-gallery-wires-test-B7SeUCc8.js +0 -148
  639. package/bundled-test-harness/assets/client-telemetry-test-DGmHzAFx.js +0 -340
  640. package/bundled-test-harness/assets/clip-BpYQPVz_.js +0 -2
  641. package/bundled-test-harness/assets/clip-CNaYbIwL.js +0 -92
  642. package/bundled-test-harness/assets/code-block-Cp2CJo5-.js +0 -502
  643. package/bundled-test-harness/assets/code-ref-test-C8JBHDb-.js +0 -163
  644. package/bundled-test-harness/assets/code-submode-availability-test-CzG1Tv6L.js +0 -198
  645. package/bundled-test-harness/assets/code-submode-test-BclVWjm5.js +0 -1839
  646. package/bundled-test-harness/assets/codeblocks-test-CmQlyxN7.js +0 -418
  647. package/bundled-test-harness/assets/codemirror-editor-test-B74H_yn8.js +0 -1512
  648. package/bundled-test-harness/assets/codemirror-embed-toolbar-test-Bz6VEysU.js +0 -366
  649. package/bundled-test-harness/assets/color-field-test-DMCPQKIP.js +0 -212
  650. package/bundled-test-harness/assets/compaction-test-saQCLBrQ.js +0 -150
  651. package/bundled-test-harness/assets/computed-test-C05HliJC.js +0 -1320
  652. package/bundled-test-harness/assets/container-Cqcwrd-m.js +0 -10857
  653. package/bundled-test-harness/assets/content-preview-components-test-DZPj4_CU.js +0 -462
  654. package/bundled-test-harness/assets/copy-and-edit-test-DiXTQNTF.js +0 -292
  655. package/bundled-test-harness/assets/copy-card-test-ys7GquUY.js +0 -218
  656. package/bundled-test-harness/assets/copy-file-to-realm-test-Gn0Wn4vT.js +0 -148
  657. package/bundled-test-harness/assets/copy-source-test-BTLrOmPm.js +0 -56
  658. package/bundled-test-harness/assets/create-file-test-BCeIW-Rt.js +0 -464
  659. package/bundled-test-harness/assets/create-file-test-DbHQ5JsS.js +0 -1086
  660. package/bundled-test-harness/assets/create-listing-modal-test-CeHc4ter.js +0 -273
  661. package/bundled-test-harness/assets/create-listing-pr-request-test-DXbJNfMh.js +0 -117
  662. package/bundled-test-harness/assets/create-spec-test-BDIZoyHT.js +0 -256
  663. package/bundled-test-harness/assets/create-submission-workflow-test-Bix5J-3A.js +0 -132
  664. package/bundled-test-harness/assets/create-workspace-test-BmNnLHwC.js +0 -104
  665. package/bundled-test-harness/assets/credential-fields-test-NK1F4QWn.js +0 -200
  666. package/bundled-test-harness/assets/csv-file-def-test-BSfs4TTP.js +0 -102
  667. package/bundled-test-harness/assets/dashboard-C4T7ffKY.js +0 -3576
  668. package/bundled-test-harness/assets/dashboard-CFeHuP5-.js +0 -81
  669. package/bundled-test-harness/assets/dashboard-DQlpW-ux.css +0 -2392
  670. package/bundled-test-harness/assets/dashboard-add-workspace-test--rr6objf.js +0 -50
  671. package/bundled-test-harness/assets/dashboard-agents-test-D1y8H4xH.js +0 -334
  672. package/bundled-test-harness/assets/dashboard-archive-test-bN4EQaXv.js +0 -128
  673. package/bundled-test-harness/assets/dashboard-delete-test-BvsASb8B.js +0 -163
  674. package/bundled-test-harness/assets/dashboard-duplicate-offer-test-DEsd5ZzZ.js +0 -71
  675. package/bundled-test-harness/assets/dashboard-duplicate-test-BnR0sTgB.js +0 -222
  676. package/bundled-test-harness/assets/dashboard-get-started-test-DG4uUXLv.js +0 -246
  677. package/bundled-test-harness/assets/dashboard-pinned-cards-test-AoGGVRAS.js +0 -220
  678. package/bundled-test-harness/assets/dashboard-reindex-test-BN9a96Xp.js +0 -115
  679. package/bundled-test-harness/assets/dashboard-section-rail-test-B3OT9V2T.js +0 -169
  680. package/bundled-test-harness/assets/dashboard-state-test-BY0Zqrmj.js +0 -162
  681. package/bundled-test-harness/assets/dashboard-test-C13oNpWt.js +0 -545
  682. package/bundled-test-harness/assets/dashboard-unreachable-notice-test-DZIV4x5j.js +0 -62
  683. package/bundled-test-harness/assets/dashboard-workspace-test-CBnOQViI.js +0 -537
  684. package/bundled-test-harness/assets/dashboard-workspaces-section-test-KU8ZVOYp.js +0 -396
  685. package/bundled-test-harness/assets/data-file-def-preview-test-CI5gcdtK.js +0 -155
  686. package/bundled-test-harness/assets/date-time-fields-test-D2CpR_Pb.js +0 -359
  687. package/bundled-test-harness/assets/debug-message-test-Df1kHesw.js +0 -117
  688. package/bundled-test-harness/assets/declared-captures-test-hQ43zuox.js +0 -879
  689. package/bundled-test-harness/assets/delete-workspace-test-BhfMKsix.js +0 -102
  690. package/bundled-test-harness/assets/diffing-test-CHRh55mC.js +0 -210
  691. package/bundled-test-harness/assets/download-file-to-realm-test-CC1HURCi.js +0 -119
  692. package/bundled-test-harness/assets/editor-test-DkeCv28f.js +0 -688
  693. package/bundled-test-harness/assets/edits-BSJqtUXM.js +0 -651
  694. package/bundled-test-harness/assets/email-field-test-DihK0suO.js +0 -75
  695. package/bundled-test-harness/assets/enum-field-test-Gja3bzt5.js +0 -935
  696. package/bundled-test-harness/assets/error-display-test-GhYZu7cp.js +0 -343
  697. package/bundled-test-harness/assets/evaluate-module-test-D_t4CiUq.js +0 -91
  698. package/bundled-test-harness/assets/execute-atomic-operations-test-xtou8Zeg.js +0 -113
  699. package/bundled-test-harness/assets/externals-B02-sD_L.js +0 -4393
  700. package/bundled-test-harness/assets/fallback-banner-live-delete-test-DtxzNXdE.js +0 -207
  701. package/bundled-test-harness/assets/fallback-banner-test-BfmiQ_68.js +0 -53
  702. package/bundled-test-harness/assets/fallback-banner-test-DLtTdmvn.js +0 -225
  703. package/bundled-test-harness/assets/fallback-models-test-BxNJxhfd.js +0 -161
  704. package/bundled-test-harness/assets/fetch-card-json-test-DofKbzvC.js +0 -61
  705. package/bundled-test-harness/assets/field-configuration-test-SUoPaXWy.js +0 -551
  706. package/bundled-test-harness/assets/field-markdown-domain-test-BwtR0dPP.js +0 -616
  707. package/bundled-test-harness/assets/field-markdown-oversize-test-D8UJcBc3.js +0 -88
  708. package/bundled-test-harness/assets/field-markdown-primitives-test-D5_ZdoDO.js +0 -365
  709. package/bundled-test-harness/assets/field-markdown-specialized-test-Dpd5hs04.js +0 -534
  710. package/bundled-test-harness/assets/field-playground-test-CzhYzKGv.js +0 -894
  711. package/bundled-test-harness/assets/field-support-predicates-test-BSvVOFth.js +0 -167
  712. package/bundled-test-harness/assets/file-attachment-test-fM-yFedm.js +0 -796
  713. package/bundled-test-harness/assets/file-chooser-panel-test-CKj8YTdY.js +0 -153
  714. package/bundled-test-harness/assets/file-chooser-test-Bs8jFXqa.js +0 -504
  715. package/bundled-test-harness/assets/file-def-format-templates-test-CxrRoWoD.js +0 -380
  716. package/bundled-test-harness/assets/file-def-live-reload-test-X_8YEkve.js +0 -124
  717. package/bundled-test-harness/assets/file-def-menu-items-test-Dx879o_o.js +0 -138
  718. package/bundled-test-harness/assets/file-def-navigation-test-MMI_EEO1.js +0 -109
  719. package/bundled-test-harness/assets/file-def-serialization-test-B5lguBQD.js +0 -89
  720. package/bundled-test-harness/assets/file-def-test-Di9QWcrj.js +0 -216
  721. package/bundled-test-harness/assets/file-preview-live-reload-test-aqx93A7c.js +0 -310
  722. package/bundled-test-harness/assets/file-resource-primitives-test-a5abpcSB.js +0 -255
  723. package/bundled-test-harness/assets/file-tree-from-index-test-CnruGxJ8.js +0 -96
  724. package/bundled-test-harness/assets/file-tree-test-BCyWDdSE.js +0 -851
  725. package/bundled-test-harness/assets/file-view-model-test-BfpLa01Y.js +0 -346
  726. package/bundled-test-harness/assets/filedef-export-shape-test-CQ9XbrzS.js +0 -61
  727. package/bundled-test-harness/assets/film-CL1zj_bJ.js +0 -2
  728. package/bundled-test-harness/assets/film-Dq_quZ31.js +0 -13
  729. package/bundled-test-harness/assets/film-xbkQa060.js +0 -4074
  730. package/bundled-test-harness/assets/flac-audio-def-test-BmVp9dMx.js +0 -143
  731. package/bundled-test-harness/assets/focus-Dm4wkM72.js +0 -306
  732. package/bundled-test-harness/assets/font-metadata-extractor-test-OWEh9_MS.js +0 -415
  733. package/bundled-test-harness/assets/formatted-aibot-message-test-BpHsWpuV.js +0 -109
  734. package/bundled-test-harness/assets/formatted-user-message-test-DZW5TAr0.js +0 -43
  735. package/bundled-test-harness/assets/freestyle-test-D_uaPU_3.js +0 -17
  736. package/bundled-test-harness/assets/full-reindex-realm-test-C6vHL5kC.js +0 -101
  737. package/bundled-test-harness/assets/garbage-collection-test-D-Ao4t2n.js +0 -403
  738. package/bundled-test-harness/assets/general-test-PSGI8W0z.js +0 -923
  739. package/bundled-test-harness/assets/generate-example-cards-one-shot-test-J-m-0E6W.js +0 -65
  740. package/bundled-test-harness/assets/generic-file-def-preview-test-BAsOhTYU.js +0 -71
  741. package/bundled-test-harness/assets/get-available-realm-identifiers-test-D5PBOr97.js +0 -47
  742. package/bundled-test-harness/assets/get-catalog-realm-identifiers-test-NM9UURHE.js +0 -47
  743. package/bundled-test-harness/assets/get-default-writable-realm-test-BxXc9a3J.js +0 -54
  744. package/bundled-test-harness/assets/get-published-realms-test-C8TJEc4-.js +0 -71
  745. package/bundled-test-harness/assets/get-realm-of-resource-identifier-test-Dt8CB6lS.js +0 -54
  746. package/bundled-test-harness/assets/get-relationship-membership-state-test-9_8x3myJ.js +0 -1308
  747. package/bundled-test-harness/assets/get-user-system-card-test-k0UO-uba.js +0 -67
  748. package/bundled-test-harness/assets/gif-image-def-test-BWrqPGDX.js +0 -188
  749. package/bundled-test-harness/assets/glimmer-motion-and-choreo-in-cards-test-BgG8QI9E.js +0 -160
  750. package/bundled-test-harness/assets/glimmer-motion-and-choreo-test-BKOvNyCN.js +0 -74
  751. package/bundled-test-harness/assets/gts-file-def-test-BCRHwDeZ.js +0 -100
  752. package/bundled-test-harness/assets/head-format-preview-test-DnfUhniI.js +0 -158
  753. package/bundled-test-harness/assets/helpers-DklkegO_.js +0 -5
  754. package/bundled-test-harness/assets/host-mode-service-vOfN0smp.js +0 -232
  755. package/bundled-test-harness/assets/host-mode-test-CCCJFz6_.js +0 -831
  756. package/bundled-test-harness/assets/host-submode-test-CtCfbuPA.js +0 -1342
  757. package/bundled-test-harness/assets/html-component-test-CWyhb5ZX.js +0 -65
  758. package/bundled-test-harness/assets/html-def-test-Cb8C2lUx.js +0 -160
  759. package/bundled-test-harness/assets/html-meta-extractor-test-BHT9Rtir.js +0 -60
  760. package/bundled-test-harness/assets/hydratable-card-test-DpgpdesD.js +0 -426
  761. package/bundled-test-harness/assets/icon-button-ABCGVF3C.js +0 -67
  762. package/bundled-test-harness/assets/image-metadata-extractor-test-ClhPTouq.js +0 -1109
  763. package/bundled-test-harness/assets/index-changes-test-CgnVr3LH.js +0 -367
  764. package/bundled-test-harness/assets/index-query-engine-test-CQTwju5_.js +0 -2593
  765. package/bundled-test-harness/assets/index-writer-test-IoVOoZT2.js +0 -3040
  766. package/bundled-test-harness/assets/inspector-test-BN2Ieb77.js +0 -2058
  767. package/bundled-test-harness/assets/instance-filter-matcher-test-Bq-_Sy89.js +0 -788
  768. package/bundled-test-harness/assets/instantiate-card-test-DEeDTzFV.js +0 -164
  769. package/bundled-test-harness/assets/interact-submode-creation-and-permissions-test-DP6kOyJS.js +0 -475
  770. package/bundled-test-harness/assets/interact-submode-setup-B0_cHqH-.js +0 -566
  771. package/bundled-test-harness/assets/invalidate-realm-identifiers-test-9uUD91Pw.js +0 -99
  772. package/bundled-test-harness/assets/invite-user-to-room-test-CcDA45Ac.js +0 -142
  773. package/bundled-test-harness/assets/invoke-card-operation-test-DmUtgueM.js +0 -333
  774. package/bundled-test-harness/assets/isolated-render-test-B2eXNHu6.js +0 -51
  775. package/bundled-test-harness/assets/job-scoped-doc-cache-test-DF9D7cOc.js +0 -181
  776. package/bundled-test-harness/assets/job-scoped-instance-residency-test-CSS8xUU5.js +0 -103
  777. package/bundled-test-harness/assets/jpg-image-def-test-voECMTht.js +0 -697
  778. package/bundled-test-harness/assets/json-file-def-test-8Y4KLjUC.js +0 -95
  779. package/bundled-test-harness/assets/key-notices-badge-test-d1mYqx0e.js +0 -155
  780. package/bundled-test-harness/assets/key-readiness-test-BtCg7PCk.js +0 -190
  781. package/bundled-test-harness/assets/linksto-broken-link-placeholder-test-CyCMbJnN.js +0 -398
  782. package/bundled-test-harness/assets/linksto-error-sentinel-test-BDW572-v.js +0 -238
  783. package/bundled-test-harness/assets/linksto-many-broken-link-placeholder-test-B4wM97hD.js +0 -354
  784. package/bundled-test-harness/assets/linksto-many-per-slot-access-test-BhJmtJ0_.js +0 -303
  785. package/bundled-test-harness/assets/linksto-sentinel-reload-test-BpBQ5V_i.js +0 -197
  786. package/bundled-test-harness/assets/linksto-sentinel-roundtrip-test-pkBBl4e9.js +0 -260
  787. package/bundled-test-harness/assets/linksto-singular-js-access-contract-test-Bb6wjUdD.js +0 -196
  788. package/bundled-test-harness/assets/lint-and-fix-test-CcMLn-co.js +0 -51
  789. package/bundled-test-harness/assets/live-test-AyBnq7BX.js +0 -2
  790. package/bundled-test-harness/assets/live-test-CgnAcIDw.js +0 -100
  791. package/bundled-test-harness/assets/load-default-skills-test-BIOwtx0Y.js +0 -74
  792. package/bundled-test-harness/assets/loader-parallel-prefetch-test-D5_oRSER.js +0 -257
  793. package/bundled-test-harness/assets/loader-test-DSc_jR1c.js +0 -482
  794. package/bundled-test-harness/assets/loading-test-8pldx7S-.js +0 -63
  795. package/bundled-test-harness/assets/m4a-audio-def-test-BDI5apzM.js +0 -190
  796. package/bundled-test-harness/assets/main-5kHyCkdm.js +0 -5
  797. package/bundled-test-harness/assets/markdown-embed-chooser-modal-test-Wud0s7WZ.js +0 -470
  798. package/bundled-test-harness/assets/markdown-embed-chooser-test-DVzzS-0C.js +0 -334
  799. package/bundled-test-harness/assets/markdown-embed-preview-pane-test-B5W_iqsi.js +0 -447
  800. package/bundled-test-harness/assets/markdown-embed-preview-test-CZF_s0fB.js +0 -368
  801. package/bundled-test-harness/assets/markdown-fallback-test-fT6BS4W7.js +0 -316
  802. package/bundled-test-harness/assets/markdown-file-def-test-B1aTzazR.js +0 -380
  803. package/bundled-test-harness/assets/markdown-helpers-test-gNKZf7Mw.js +0 -188
  804. package/bundled-test-harness/assets/markdown-highlighting-test-Du5_CQmD.js +0 -244
  805. package/bundled-test-harness/assets/markdown-preview-h-_aJhRc.js +0 -72
  806. package/bundled-test-harness/assets/markdown-preview-test-DJvoVsXw.js +0 -238
  807. package/bundled-test-harness/assets/markdown-skill-frontmatter-test-VwJi3Paj.js +0 -146
  808. package/bundled-test-harness/assets/markdown-skill-search-test-ysCdf0xM.js +0 -80
  809. package/bundled-test-harness/assets/matrix-service-account-switch-sessions-test-K2JuMy36.js +0 -63
  810. package/bundled-test-harness/assets/matrix-service-boot-assembly-test-CkdL_-os.js +0 -300
  811. package/bundled-test-harness/assets/matrix-service-personal-realm-test-Dy1DultK.js +0 -125
  812. package/bundled-test-harness/assets/matrix-service-realm-servers-test-DHDDKuEg.js +0 -55
  813. package/bundled-test-harness/assets/matrix-service-realms-list-updated-test-DcTbZpMl.js +0 -132
  814. package/bundled-test-harness/assets/matrix-service-relogin-test-D3NQktoa.js +0 -59
  815. package/bundled-test-harness/assets/matrix-service-sliding-sync-test-6CAflWOA.js +0 -35
  816. package/bundled-test-harness/assets/menu-kUSaJIPq.js +0 -3562
  817. package/bundled-test-harness/assets/message-service-subscription-test-DaQdgDWi.js +0 -110
  818. package/bundled-test-harness/assets/message-service-test-BsGEgM_m.js +0 -144
  819. package/bundled-test-harness/assets/message-tool-test-BB_4kw1V.js +0 -33
  820. package/bundled-test-harness/assets/midi-audio-def-test-BbbkFjqf.js +0 -182
  821. package/bundled-test-harness/assets/migrate-skill-test-X9xImDuq.js +0 -161
  822. package/bundled-test-harness/assets/mini-AwF31elJ.js +0 -1404
  823. package/bundled-test-harness/assets/mini-card-chooser-test-BZtrEiWu.js +0 -272
  824. package/bundled-test-harness/assets/mini-file-chooser-test-MIHW3kCI.js +0 -201
  825. package/bundled-test-harness/assets/mock-matrix-Dd8k0DNa.js +0 -15107
  826. package/bundled-test-harness/assets/mock-matrix-DhPN_34j.js +0 -2
  827. package/bundled-test-harness/assets/modal-LTh3_oHK.js +0 -322
  828. package/bundled-test-harness/assets/model-cost-tier-test-h1IkU9mp.js +0 -174
  829. package/bundled-test-harness/assets/model-file-extract-test-ntSo0wZF.js +0 -206
  830. package/bundled-test-harness/assets/module-transpile-cache-test-CDeRaaeP.js +0 -67
  831. package/bundled-test-harness/assets/monaco-test-C0Fa744D.js +0 -100
  832. package/bundled-test-harness/assets/mp3-audio-def-test-B4j4qR9H.js +0 -133
  833. package/bundled-test-harness/assets/multiple-stacks-test-BhA25ywL.js +0 -208
  834. package/bundled-test-harness/assets/nested-query-field-render-test-S9Y8YNKB.js +0 -249
  835. package/bundled-test-harness/assets/no-stacks-test-B7VciWyg.js +0 -48
  836. package/bundled-test-harness/assets/number-field-test-CS74lDPN.js +0 -184
  837. package/bundled-test-harness/assets/office-file-def-test-2cKc1pmd.js +0 -263
  838. package/bundled-test-harness/assets/office-metadata-extractor-test-DC8Fo-OW.js +0 -218
  839. package/bundled-test-harness/assets/office-poster-capture-test-Ba0_5UrT.js +0 -203
  840. package/bundled-test-harness/assets/ogg-audio-def-test-CIPQ1d4w.js +0 -196
  841. package/bundled-test-harness/assets/open-create-listing-modal-test-bmQkY5Zl.js +0 -131
  842. package/bundled-test-harness/assets/open-image-in-new-tab-test-DBD7_vMH.js +0 -52
  843. package/bundled-test-harness/assets/open-secure-window-test-BgeuYAqz.js +0 -253
  844. package/bundled-test-harness/assets/open-workspace-test-DRHGljV0.js +0 -46
  845. package/bundled-test-harness/assets/operation-lowering-test-CH1c0pSH.js +0 -2957
  846. package/bundled-test-harness/assets/operations-invocation-test-B1YkCLrv.js +0 -523
  847. package/bundled-test-harness/assets/operations-optimistic-test-DAbtOwsC.js +0 -203
  848. package/bundled-test-harness/assets/operations-query-test-9p1ZIDe-.js +0 -459
  849. package/bundled-test-harness/assets/operations-store-reconciliation-test-D0EQh3w2.js +0 -406
  850. package/bundled-test-harness/assets/operations-test-BQhlrfe3.js +0 -2518
  851. package/bundled-test-harness/assets/operator-mode-acceptance-test-DtHnonEb.js +0 -1195
  852. package/bundled-test-harness/assets/operator-mode-card-chooser-test-DQUxZxaq.js +0 -1036
  853. package/bundled-test-harness/assets/operator-mode-links-test-BJ26HllS.js +0 -797
  854. package/bundled-test-harness/assets/operator-mode-test-DIPDI0qt.js +0 -696
  855. package/bundled-test-harness/assets/operator-mode-ui-test-CfA-fAh4.js +0 -1045
  856. package/bundled-test-harness/assets/overlay-DecPh3nt.js +0 -123
  857. package/bundled-test-harness/assets/overlay-menu-items-test-C6XqjLtu.js +0 -331
  858. package/bundled-test-harness/assets/overlays-Ctp8ePzZ.js +0 -75
  859. package/bundled-test-harness/assets/overlays-CzWpSg5T.js +0 -2
  860. package/bundled-test-harness/assets/overlays-detached-element-test-DvL_8Bb5.js +0 -56
  861. package/bundled-test-harness/assets/panel-CImumikB.js +0 -15124
  862. package/bundled-test-harness/assets/past-sessions-test-N6riGN_I.js +0 -321
  863. package/bundled-test-harness/assets/patch-fields-test-D30_-KwQ.js +0 -1014
  864. package/bundled-test-harness/assets/patch-instance-test-C5rGscZq.js +0 -348
  865. package/bundled-test-harness/assets/pdf-file-def-test-DtiqGRvZ.js +0 -111
  866. package/bundled-test-harness/assets/pdf-metadata-extractor-test-FU02KmdV.js +0 -130
  867. package/bundled-test-harness/assets/permission-checking-realm-test-DqdNJDwU.js +0 -306
  868. package/bundled-test-harness/assets/persist-module-inspector-view-test-BHOAgPVy.js +0 -60
  869. package/bundled-test-harness/assets/persist-scroll-position-test-qtmS518r.js +0 -254
  870. package/bundled-test-harness/assets/phone-number-field-test-DhdaM7uL.js +0 -73
  871. package/bundled-test-harness/assets/pill-menu-test-C9Mrrepl.js +0 -60
  872. package/bundled-test-harness/assets/plate-9n-sXyCw.js +0 -41
  873. package/bundled-test-harness/assets/plate-BnZcAk-_.js +0 -2
  874. package/bundled-test-harness/assets/player-Cu5b4LEJ.js +0 -82
  875. package/bundled-test-harness/assets/player-unk2mkxV.js +0 -2
  876. package/bundled-test-harness/assets/playground-BwA8wFGK.js +0 -58
  877. package/bundled-test-harness/assets/plural-field-components-test-CFNQKETg.js +0 -198
  878. package/bundled-test-harness/assets/png-image-def-test-DG5Vhlqb.js +0 -266
  879. package/bundled-test-harness/assets/policy-audit-confirmation-test-yfKU47LR.js +0 -155
  880. package/bundled-test-harness/assets/policy-scoped-search-test-BjQRDYqR.js +0 -339
  881. package/bundled-test-harness/assets/prerender-file-extract-test-CEU4SaAZ.js +0 -346
  882. package/bundled-test-harness/assets/prerender-html-test-CGB3ClCS.js +0 -670
  883. package/bundled-test-harness/assets/prerender-meta-test-xqc4fW_0.js +0 -614
  884. package/bundled-test-harness/assets/prerender-module-test-CI1TmZw-.js +0 -409
  885. package/bundled-test-harness/assets/prerender-persistence-block-test-Da0dJO_N.js +0 -124
  886. package/bundled-test-harness/assets/prerender-pre-model-error-test-BVLyhk8R.js +0 -61
  887. package/bundled-test-harness/assets/prerender-serialize-cycle-test-glJFfxHU.js +0 -134
  888. package/bundled-test-harness/assets/prerendered-html-read-test-Mp4L0VHQ.js +0 -191
  889. package/bundled-test-harness/assets/pretui-components-test-BBpA9UnA.js +0 -991
  890. package/bundled-test-harness/assets/pretui-components-test-BqFq7rw_.css +0 -730
  891. package/bundled-test-harness/assets/preview-format-test-C55Bwcur.js +0 -103
  892. package/bundled-test-harness/assets/preview-test-CTAhRGU8.js +0 -474
  893. package/bundled-test-harness/assets/process-card-test-UjqpuxB7.js +0 -94
  894. package/bundled-test-harness/assets/profile-settings-modal-C8bCgTMK.js +0 -989
  895. package/bundled-test-harness/assets/publish-realm-ixUB4FPK.js +0 -82
  896. package/bundled-test-harness/assets/publish-realm-test-CrrsdL4W.js +0 -210
  897. package/bundled-test-harness/assets/query-field-barrier-test-DjivFE93.js +0 -113
  898. package/bundled-test-harness/assets/query-field-error-sentinel-test-0HwnV4Mw.js +0 -201
  899. package/bundled-test-harness/assets/query-field-membership-status-test-C8yTTBkc.js +0 -323
  900. package/bundled-test-harness/assets/query-field-page-optin-test-D4l_GcII.js +0 -126
  901. package/bundled-test-harness/assets/query-field-schema-test-DDbcNNm5.js +0 -231
  902. package/bundled-test-harness/assets/query-field-search-throttle-test-CXp50Ax0.js +0 -154
  903. package/bundled-test-harness/assets/query-field-stale-prerender-test-DErzt-Cv.js +0 -152
  904. package/bundled-test-harness/assets/query-fields-test-Dz67fdSl.js +0 -535
  905. package/bundled-test-harness/assets/quick-look-test-B1ijDsh_.js +0 -139
  906. package/bundled-test-harness/assets/read-card-for-ai-assistant-test-DJxZ16H_.js +0 -91
  907. package/bundled-test-harness/assets/read-file-for-ai-assistant-test-BoRQkZ8c.js +0 -45
  908. package/bundled-test-harness/assets/read-source-test-Bl-NjchO.js +0 -67
  909. package/bundled-test-harness/assets/read-text-file-test-CP37CZoo.js +0 -124
  910. package/bundled-test-harness/assets/realm-CaK5mkT-.js +0 -2852
  911. package/bundled-test-harness/assets/realm-api-keys-BNUFWbGR.js +0 -579
  912. package/bundled-test-harness/assets/realm-api-keys-CkshxhXC.js +0 -2
  913. package/bundled-test-harness/assets/realm-api-keys-test-BP8xifjn.js +0 -109
  914. package/bundled-test-harness/assets/realm-api-keys-test-CwdK9YXp.js +0 -588
  915. package/bundled-test-harness/assets/realm-config-iKwE3Htp.js +0 -833
  916. package/bundled-test-harness/assets/realm-config-policy-standing-test-BgVEIDnB.js +0 -290
  917. package/bundled-test-harness/assets/realm-config-routing-rule-edit-test-BoJoKzmX.js +0 -274
  918. package/bundled-test-harness/assets/realm-config-settings-test-Kxw-GHye.js +0 -187
  919. package/bundled-test-harness/assets/realm-field-test-CdGOxrFb.js +0 -100
  920. package/bundled-test-harness/assets/realm-indexing-test-CHtsBV2b.js +0 -4380
  921. package/bundled-test-harness/assets/realm-policy-fitted-test--DhNZSdC.js +0 -206
  922. package/bundled-test-harness/assets/realm-policy-test-D7714iVa.js +0 -1141
  923. package/bundled-test-harness/assets/realm-querying-test-Cj1ekZ0H.js +0 -1067
  924. package/bundled-test-harness/assets/realm-server-form-agnostic-test-CZFPNJfD.js +0 -96
  925. package/bundled-test-harness/assets/realm-server-subscriber-test-C86WmBp0.js +0 -46
  926. package/bundled-test-harness/assets/realm-service-info-test-CdgcwKDR.js +0 -67
  927. package/bundled-test-harness/assets/realm-test-DPoLsvKz.js +0 -2364
  928. package/bundled-test-harness/assets/realm-token-refresh-test-Ch35Siwi.js +0 -153
  929. package/bundled-test-harness/assets/realm-url-tooltip-test-x8xWOENK.js +0 -78
  930. package/bundled-test-harness/assets/reasoning-test-BxpE8Jvf.js +0 -221
  931. package/bundled-test-harness/assets/recent-files-test-DTmEzPLq.js +0 -450
  932. package/bundled-test-harness/assets/reindex-realm-test-BQ8KULn4.js +0 -117
  933. package/bundled-test-harness/assets/relationship-loading-state-test-BJoArPWf.js +0 -290
  934. package/bundled-test-harness/assets/remix-card-test-DsTA1KoG.js +0 -58
  935. package/bundled-test-harness/assets/rendered-markdown-DvukulDO.js +0 -292
  936. package/bundled-test-harness/assets/rendered-markdown-test-DxGptXSV.js +0 -587
  937. package/bundled-test-harness/assets/resident-instance-reuse-test-ZWnVu8uj.js +0 -82
  938. package/bundled-test-harness/assets/result-tile-CPyI6Vmv.js +0 -144
  939. package/bundled-test-harness/assets/rich-markdown-field-test-CdygoXIO.js +0 -1647
  940. package/bundled-test-harness/assets/room-message-test-D3NfMqH0.js +0 -484
  941. package/bundled-test-harness/assets/run-D_Px28eF.js +0 -3956
  942. package/bundled-test-harness/assets/run-realm-code-qWCZxmJ7.js +0 -2964
  943. package/bundled-test-harness/assets/run-realm-code-test-UzyeEJq6.js +0 -3844
  944. package/bundled-test-harness/assets/sanitize-module-list-test-Babq44bP.js +0 -85
  945. package/bundled-test-harness/assets/save-card-skip-index-wait-test-BcELXlQ_.js +0 -89
  946. package/bundled-test-harness/assets/schema-editor-test-CEvruZbt.js +0 -785
  947. package/bundled-test-harness/assets/schema-generation-test-hYAMdCrn.js +0 -28
  948. package/bundled-test-harness/assets/scrolling-test-DVIsh-_1.js +0 -412
  949. package/bundled-test-harness/assets/search-adorn-test-CkVhqFd0.js +0 -136
  950. package/bundled-test-harness/assets/search-and-choose-test-DUhOB3FV.js +0 -154
  951. package/bundled-test-harness/assets/search-correlation-id-test-Drn4r26N.js +0 -139
  952. package/bundled-test-harness/assets/search-entries-result-test-DTCRJ_wc.js +0 -234
  953. package/bundled-test-harness/assets/search-entries-test-CE0B47pw.js +0 -1486
  954. package/bundled-test-harness/assets/search-entries-tool-test-C4aG0ckM.js +0 -504
  955. package/bundled-test-harness/assets/search-google-images-test-LyhcB2f3.js +0 -166
  956. package/bundled-test-harness/assets/search-results-D4pSne0x.js +0 -266
  957. package/bundled-test-harness/assets/search-results-test-CRZHhqhn.js +0 -578
  958. package/bundled-test-harness/assets/search-selection-menu-test-B7Y3E_nj.js +0 -108
  959. package/bundled-test-harness/assets/search-sheet-files-test-C2y534g8.js +0 -126
  960. package/bundled-test-harness/assets/search-sheet-persistence-test-DePC59Bk.js +0 -131
  961. package/bundled-test-harness/assets/search-test-Dy8NxFkU.js +0 -2249
  962. package/bundled-test-harness/assets/search-tool-test-lctDaMH3.js +0 -156
  963. package/bundled-test-harness/assets/searchable-option-test-CE64M8oM.js +0 -322
  964. package/bundled-test-harness/assets/searchable-search-doc-test-C6u3mVvT.js +0 -1271
  965. package/bundled-test-harness/assets/section-rail-B_UQX00B.js +0 -113
  966. package/bundled-test-harness/assets/section-rail-test-DIda7MIw.js +0 -256
  967. package/bundled-test-harness/assets/secure-sign-in-CqqqfQG8.js +0 -174
  968. package/bundled-test-harness/assets/secure-sign-in-test-DimbVr_W.js +0 -373
  969. package/bundled-test-harness/assets/segmented-control-iePxSdTS.js +0 -173
  970. package/bundled-test-harness/assets/select-tNs6_xwW.js +0 -175
  971. package/bundled-test-harness/assets/send-ai-assistant-message-test-2GVrMF9Z.js +0 -52
  972. package/bundled-test-harness/assets/send-bot-trigger-event-test-B_3dKfGN.js +0 -56
  973. package/bundled-test-harness/assets/send-request-via-proxy-test-_clNWyYc.js +0 -380
  974. package/bundled-test-harness/assets/sending-test-DCPFXUVg.js +0 -659
  975. package/bundled-test-harness/assets/serialization-rri-form-audit-test-BI0zCs8Y.js +0 -136
  976. package/bundled-test-harness/assets/serialization-test-bjdtVlZL.js +0 -8758
  977. package/bundled-test-harness/assets/set-user-system-card-test-BUv1vL08.js +0 -59
  978. package/bundled-test-harness/assets/setup-BW1mmC7C.js +0 -772
  979. package/bundled-test-harness/assets/setup-DsIcFT-T.js +0 -2
  980. package/bundled-test-harness/assets/shared-link-target-reuse-test-9NeJEjkb.js +0 -207
  981. package/bundled-test-harness/assets/show-card-test-mfyLwusD.js +0 -365
  982. package/bundled-test-harness/assets/signed-capture-link-test-BOtKNCAM.js +0 -132
  983. package/bundled-test-harness/assets/single-stack-test-B4MGjaLk.js +0 -652
  984. package/bundled-test-harness/assets/skills-test-BuP-Yzk1.js +0 -648
  985. package/bundled-test-harness/assets/skip-boot-index-guard-test-Cmrx2-K7.js +0 -46
  986. package/bundled-test-harness/assets/spec-test-BhZDdhVQ.js +0 -1077
  987. package/bundled-test-harness/assets/spinner-CpIBUG9m.js +0 -49
  988. package/bundled-test-harness/assets/src-DGHttmW-.js +0 -216
  989. package/bundled-test-harness/assets/src-DaNDSbp7.js +0 -5
  990. package/bundled-test-harness/assets/stick-to-bottom-resize-test-Dpy3OVum.js +0 -56
  991. package/bundled-test-harness/assets/store-add-test-_IYS8o74.js +0 -50
  992. package/bundled-test-harness/assets/store-module-rebuild-test-B5VMaICy.js +0 -454
  993. package/bundled-test-harness/assets/store-search-test-C2VZabrH.js +0 -175
  994. package/bundled-test-harness/assets/store-test-D6PObxoD.js +0 -3672
  995. package/bundled-test-harness/assets/structured-theme-test-BHjVeMf-.js +0 -377
  996. package/bundled-test-harness/assets/summarize-session-test-BFtTuhe0.js +0 -172
  997. package/bundled-test-harness/assets/svg-image-def-test-BL6lkWUX.js +0 -167
  998. package/bundled-test-harness/assets/switch-submode-test-6Uv3bZMl.js +0 -168
  999. package/bundled-test-harness/assets/sync-openrouter-models-test-Dp9E05tL.js +0 -97
  1000. package/bundled-test-harness/assets/test-support-DYm8XZ0E.js +0 -3
  1001. package/bundled-test-harness/assets/test-support-DfnhiIMV.js +0 -99
  1002. package/bundled-test-harness/assets/tests-CZk0Iag2.js +0 -3596
  1003. package/bundled-test-harness/assets/text-file-def-test-CHdC0yIU.js +0 -94
  1004. package/bundled-test-harness/assets/text-input-validator-test-B9ZR8XPU.js +0 -156
  1005. package/bundled-test-harness/assets/text-suggestion-test-CGLspKFQ.js +0 -340
  1006. package/bundled-test-harness/assets/theme-card-test-CXZvSEvG.js +0 -621
  1007. package/bundled-test-harness/assets/theme-dashboard-nav-test-CkEE0ILk.js +0 -196
  1008. package/bundled-test-harness/assets/theme-scheme-island-test-URXTjipF.js +0 -264
  1009. package/bundled-test-harness/assets/titles-C6enAdIv.js +0 -2
  1010. package/bundled-test-harness/assets/titles-Dft1HoUT.js +0 -52
  1011. package/bundled-test-harness/assets/to-device-streaming-test-D33ZOc9o.js +0 -163
  1012. package/bundled-test-harness/assets/token-usage-test-BHQlU4J4.js +0 -160
  1013. package/bundled-test-harness/assets/tools-CrudqfS3.js +0 -774
  1014. package/bundled-test-harness/assets/tools-calling-test-jo7IREau.js +0 -200
  1015. package/bundled-test-harness/assets/tools-test-D1wMfUa0.js +0 -1624
  1016. package/bundled-test-harness/assets/tools-test-Dn1LYsXp.js +0 -3204
  1017. package/bundled-test-harness/assets/tooltip-8Wyz4IIn.css +0 -68
  1018. package/bundled-test-harness/assets/tooltip-CqwLzRz5.js +0 -134
  1019. package/bundled-test-harness/assets/transform-cards-test-BPhwPFtp.js +0 -341
  1020. package/bundled-test-harness/assets/ts-file-def-preview-test-Bq3zTgw8.js +0 -95
  1021. package/bundled-test-harness/assets/ts-file-def-test-GLswMl7O.js +0 -92
  1022. package/bundled-test-harness/assets/ttf-font-def-test-DQulvUWs.js +0 -206
  1023. package/bundled-test-harness/assets/turn-settling-test-BspmOUQP.js +0 -160
  1024. package/bundled-test-harness/assets/turn-summary-9A8nvC0-.js +0 -1039
  1025. package/bundled-test-harness/assets/unpublish-realm-test-SkYPEhDz.js +0 -102
  1026. package/bundled-test-harness/assets/update-room-skills-test-cTxb-WU6.js +0 -240
  1027. package/bundled-test-harness/assets/use-ai-assistant-test-uaqW1T_A.js +0 -384
  1028. package/bundled-test-harness/assets/user-message-BudkIP-3.js +0 -262
  1029. package/bundled-test-harness/assets/validate-realm-test-DxrGgH9n.js +0 -67
  1030. package/bundled-test-harness/assets/video-metadata-extractor-test-B2pe-Iqa.js +0 -520
  1031. package/bundled-test-harness/assets/view-visually-test-PNon6fUo.js +0 -335
  1032. package/bundled-test-harness/assets/virtual-network-reset-test-uYJLaQHf.js +0 -96
  1033. package/bundled-test-harness/assets/wav-audio-def-test-F4OrFFR4.js +0 -160
  1034. package/bundled-test-harness/assets/webp-image-def-test-B0a_-Vya.js +0 -226
  1035. package/bundled-test-harness/assets/workspace-Cyftysy9.js +0 -440
  1036. package/bundled-test-harness/assets/workspace-a11y-test-sKiPDcbl.js +0 -197
  1037. package/bundled-test-harness/assets/workspace-actions-BuawjFmZ.js +0 -561
  1038. package/bundled-test-harness/assets/workspace-behavior-test-CKa-pb3T.js +0 -338
  1039. package/bundled-test-harness/assets/workspace-delete-multiple-test-Dt2weG5R.js +0 -212
  1040. package/bundled-test-harness/assets/workspace-delete-summary-test-CkqgFqZ8.js +0 -63
  1041. package/bundled-test-harness/assets/workspace-hosting-test-Ci7EEtHP.js +0 -138
  1042. package/bundled-test-harness/assets/workspace-indexing-test-BPVxxY6W.js +0 -71
  1043. package/bundled-test-harness/assets/workspace-test-CWr7vFbg.js +0 -385
  1044. package/bundled-test-harness/assets/workspace-test-INNpQovc.js +0 -51
  1045. package/bundled-test-harness/assets/workspace-timestamp-labels-test-CigQb5wr.js +0 -68
  1046. package/bundled-test-harness/assets/workspace-unit-test-BwVKpuXT.js +0 -122
  1047. package/bundled-test-harness/assets/write-binary-file-test-BKP3gv1k.js +0 -124
  1048. package/bundled-test-harness/assets/write-text-file-test-B6ijTKTa.js +0 -191
  1049. package/bundled-test-harness/assets/zip-archive-test-C-PBzkTn.js +0 -285
  1050. package/bundled-test-harness/assets/zip-file-def-test-FyCzJT-9.js +0 -164
@@ -1,3844 +0,0 @@
1
- import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
- import { Br as testRealmURL, Co as SupportedMimeType, Fn as APP_BOXEL_ACTIVE_LLM, fr as CAPTURE_SOURCE_URL_PREFIX, nr as APP_BOXEL_ROOM_SKILLS_EVENT_TYPE, pr as DEFAULT_FALLBACK_MODELS, yr as LOCAL_SOURCE_URL_PREFIX } from "./runtime-common-BTaLJEw-.js";
3
- import { M as waitUntil, T as settled } from "./dist-BOAdzfkP.js";
4
- import { r as runRealmCode, t as RunRealmCodeTool } from "./run-realm-code-qWCZxmJ7.js";
5
- import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
6
- import { F as setupLocalIndexing, L as setupRealmCacheTeardown, P as setupIntegrationTestRealm, R as setupRealmServerEndpoints, Tt as testRealmSecretSeed, Z as withCachedRealmSetup, bt as resetCatalogRealmURL, lt as setupRenderingTest, t as setupMockMatrix, wt as createJWT, xt as setCatalogRealmURL } from "./mock-matrix-Dd8k0DNa.js";
7
- import { r as getService } from "./dist-CPfIHBla.js";
8
- //#region tests/integration/tools/run-realm-code-test.gts
9
- var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
10
- var otherRealmURL = "http://test-realm/test2/";
11
- function knowReadableWorkspace(identifier, permissions = ["read"]) {
12
- getService("realm").getOrCreateRealmResource(identifier, createJWT({
13
- user: "@testuser:localhost",
14
- realm: identifier,
15
- sessionRoom: "boxel-session-room-id",
16
- permissions,
17
- realmServerURL: "http://test-realm/"
18
- }, "1d", testRealmSecretSeed), { exact: true });
19
- }
20
- function recipeJSON(name, attributes, chef, module = "../recipe", helpers = []) {
21
- let relationships = {};
22
- if (chef) relationships.chef = { links: { self: chef } };
23
- helpers.forEach((helper, index) => {
24
- relationships[`helpers.${index}`] = { links: { self: helper } };
25
- });
26
- return `${JSON.stringify({ data: {
27
- type: "card",
28
- attributes,
29
- ...Object.keys(relationships).length ? { relationships } : {},
30
- meta: { adoptsFrom: {
31
- module,
32
- name
33
- } }
34
- } }, null, 2)}\n`;
35
- }
36
- var UNINDEXED_PET = JSON.stringify({ data: {
37
- type: "card",
38
- attributes: { name: "Biscuit" },
39
- meta: { adoptsFrom: {
40
- module: "../pet",
41
- name: "Pet"
42
- } }
43
- } });
44
- function readCardScript(path) {
45
- return `try { return await realm.cards.get(${JSON.stringify(path)}); } catch (e) { return e.message; }`;
46
- }
47
- var PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";
48
- (0, import_qunit.module)("Integration | tools | run-realm-code", function(hooks) {
49
- setupRenderingTest(hooks);
50
- setupLocalIndexing(hooks);
51
- let mockMatrixUtils = setupMockMatrix(hooks, {
52
- activeRealms: [testRealmURL, otherRealmURL],
53
- autostart: true
54
- });
55
- let captureRequests = [];
56
- setupRealmServerEndpoints(hooks, [{
57
- route: "_capture",
58
- getResponse: async (req) => {
59
- captureRequests.push(await req.clone().json());
60
- return new Response(JSON.stringify({ data: {
61
- type: "capture-result",
62
- attributes: {
63
- status: "ready",
64
- base64: PNG_BASE64,
65
- width: 1,
66
- height: 1,
67
- contentType: "image/png"
68
- }
69
- } }), {
70
- status: 201,
71
- headers: { "Content-Type": "application/vnd.api+json" }
72
- });
73
- }
74
- }]);
75
- setupRealmCacheTeardown(hooks);
76
- hooks.beforeEach(function() {
77
- captureRequests = [];
78
- });
79
- let adapter;
80
- let testRealm;
81
- hooks.beforeEach(async function() {
82
- ({adapter, realm: testRealm} = await withCachedRealmSetup(async () => setupIntegrationTestRealm({
83
- mockMatrixUtils,
84
- contents: {
85
- "task.json": `{
86
- "title": "Old title",
87
- "count": 1
88
- }
89
- `,
90
- "notes/first.md": "# First\n",
91
- "images/existing.png": Uint8Array.from(atob(PNG_BASE64), (char) => char.charCodeAt(0)),
92
- "docs/report.docx": Uint8Array.from([
93
- 80,
94
- 75,
95
- 3,
96
- 4,
97
- 20,
98
- 0,
99
- 6,
100
- 0,
101
- 255,
102
- 254,
103
- 156
104
- ]),
105
- "docs/README": "Plain text with no extension\n",
106
- "docs/replacement.txt": "A replacement character: �\n",
107
- "docs/latin1.txt": Uint8Array.from([
108
- 99,
109
- 97,
110
- 102,
111
- 233,
112
- 10
113
- ]),
114
- "unformatted.gts": `import { CardDef } from "@cardstack/base/card-api"
115
- export class Unformatted extends CardDef {}
116
- `,
117
- "skills/test-skill/SKILL.md": `---
118
- name: Test Skill
119
- description: A skill a script turns on
120
- boxel:
121
- kind: skill
122
- ---
123
- # Test Skill
124
- `,
125
- "pet.gts": `
126
- import { CardDef, field, contains } from '@cardstack/base/card-api';
127
- import StringField from '@cardstack/base/string';
128
-
129
- export class Pet extends CardDef {
130
- static displayName = 'Pet';
131
- @field name = contains(StringField);
132
- }
133
- `,
134
- "Pet/mango.json": { data: {
135
- type: "card",
136
- attributes: { name: "Mango" },
137
- meta: { adoptsFrom: {
138
- module: "../pet",
139
- name: "Pet"
140
- } }
141
- } },
142
- "Spec/pet.json": { data: {
143
- type: "card",
144
- attributes: {
145
- cardTitle: "Pet",
146
- cardDescription: "A pet with a name",
147
- specType: "card",
148
- readMe: "# Pet\n\nUse Pet for any animal with a name.",
149
- ref: {
150
- module: "../pet",
151
- name: "Pet"
152
- }
153
- },
154
- meta: { adoptsFrom: {
155
- module: "@cardstack/base/spec",
156
- name: "Spec"
157
- } }
158
- } },
159
- "Plain/base-typed.json": { data: {
160
- type: "card",
161
- meta: { adoptsFrom: {
162
- module: "@cardstack/base/card-api",
163
- name: "CardDef"
164
- } }
165
- } },
166
- "recipe.gts": `
167
- import { contains, field, linksTo, linksToMany, CardDef } from "@cardstack/base/card-api";
168
- import StringField from "@cardstack/base/string";
169
-
170
- export class Chef extends CardDef {
171
- static displayName = 'Chef';
172
- @field name = contains(StringField);
173
- @field cardTitle = contains(StringField, {
174
- computeVia: function (this: Chef) {
175
- return this.name;
176
- },
177
- });
178
- }
179
-
180
- export class Recipe extends CardDef {
181
- static displayName = 'Recipe';
182
- @field name = contains(StringField);
183
- @field cuisine = contains(StringField);
184
- @field chef = linksTo(Chef);
185
- @field helpers = linksToMany(Chef);
186
- @field cardTitle = contains(StringField, {
187
- computeVia: function (this: Recipe) {
188
- return 'Recipe: ' + this.name;
189
- },
190
- });
191
- }
192
- `,
193
- "person.gts": `
194
- import { contains, field, linksTo, CardDef } from "@cardstack/base/card-api";
195
- import StringField from "@cardstack/base/string";
196
-
197
- export class Person extends CardDef {
198
- @field firstName = contains(StringField);
199
- @field friend = linksTo(() => Person);
200
- @field cardTitle = contains(StringField, {
201
- computeVia: function (this: Person) {
202
- return this.firstName;
203
- },
204
- });
205
- }
206
- `,
207
- "Chef/ana.json": recipeJSON("Chef", { name: "Ana" }),
208
- "Recipe/pancakes.json": recipeJSON("Recipe", {
209
- name: "Pancakes",
210
- cuisine: "unknown"
211
- }, "../Chef/ana"),
212
- "Recipe/ramen.json": recipeJSON("Recipe", {
213
- name: "Ramen",
214
- cuisine: "Japanese"
215
- }, void 0, "../recipe", ["../Chef/ana"]),
216
- "Recipe/desserts/tiramisu.json": recipeJSON("Recipe", {
217
- name: "Tiramisu",
218
- cuisine: "unknown"
219
- }, void 0, "../../recipe"),
220
- "people/hassan.json": { data: {
221
- attributes: { firstName: "Hassan" },
222
- relationships: { friend: { links: { self: "./mango" } } },
223
- meta: { adoptsFrom: {
224
- module: "../person",
225
- name: "Person"
226
- } }
227
- } },
228
- "people/mango.json": { data: {
229
- attributes: { firstName: "Mango" },
230
- meta: { adoptsFrom: {
231
- module: "../person",
232
- name: "Person"
233
- } }
234
- } }
235
- }
236
- })));
237
- await withCachedRealmSetup(async () => setupIntegrationTestRealm({
238
- mockMatrixUtils,
239
- realmURL: otherRealmURL,
240
- contents: { "Recipe/elsewhere.json": recipeJSON("Recipe", {
241
- name: "Elsewhere",
242
- cuisine: "unknown"
243
- }, void 0, `${testRealmURL}recipe`) }
244
- }));
245
- await getService("realm").login(testRealmURL);
246
- });
247
- (0, import_qunit.test)("realm.capture attaches a capture to the result and tells the script only what it needs", async function(assert) {
248
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
249
- realm: testRealmURL,
250
- roomId: "!room:example.com",
251
- code: `return await realm.capture('task.json');`
252
- });
253
- assert.strictEqual(captureRequests.length, 1, "one capture request");
254
- assert.strictEqual(captureRequests[0].data.attributes.fileURL, `${testRealmURL}task.json`);
255
- assert.deepEqual(JSON.parse(result.scriptResult), {
256
- path: "task.json",
257
- kind: "file",
258
- format: "isolated",
259
- viewportWidth: 1280,
260
- viewportHeight: 800,
261
- width: 1,
262
- height: 1,
263
- attached: true
264
- });
265
- assert.strictEqual(result.captures.length, 1, "the capture rides the result");
266
- assert.strictEqual(result.captures[0].contentType, "image/png");
267
- assert.ok(result.captures[0].url, "the capture is uploaded to the room");
268
- });
269
- (0, import_qunit.test)("Stop ends a run that waits on realm.ask", async function(assert) {
270
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
271
- let asked = false;
272
- let startedAt = 0;
273
- let askedAfterMs;
274
- command.onAsk = () => {
275
- asked = true;
276
- askedAfterMs = Date.now() - startedAt;
277
- return new Promise(() => void 0);
278
- };
279
- startedAt = Date.now();
280
- let run = command.execute({
281
- realm: testRealmURL,
282
- roomId: "!room:example.com",
283
- code: `await realm.ask({ question: 'Which one?', options: [{ label: 'A' }, { label: 'B' }] });
284
- return 'answered';`
285
- });
286
- let endedBeforeAsk;
287
- run.then(() => {
288
- if (!asked) endedBeforeAsk = "it returned";
289
- }, (error) => {
290
- if (!asked) endedBeforeAsk = `it failed: ${error instanceof Error ? error.message : String(error)}`;
291
- });
292
- await waitUntil(() => asked || endedBeforeAsk !== void 0, {
293
- timeout: 1e4,
294
- timeoutMessage: "the script did not ask within 10000ms"
295
- });
296
- assert.true(asked, asked ? `the script asked ${askedAfterMs}ms after the run started` : `the run ended ${Date.now() - startedAt}ms after it started, before the script asked: ${endedBeforeAsk}`);
297
- command.stop();
298
- await assert.rejects(run, /stopped/i, "the run ends without an answer");
299
- });
300
- function askThroughToolService(command, callId) {
301
- let toolService = getService("tool-service");
302
- command.onAsk = (request) => toolService.askFromScript(callId, request);
303
- }
304
- (0, import_qunit.test)("a reader's pick reaches the script as its value and its label", async function(assert) {
305
- let toolService = getService("tool-service");
306
- let command = new RunRealmCodeTool(toolService.toolContext);
307
- askThroughToolService(command, "ask-call");
308
- let run = command.execute({
309
- realm: testRealmURL,
310
- roomId: "!room:example.com",
311
- code: `return await realm.ask({ question: 'Which one?', options: [{ label: 'Alpha', value: 'a' }, { label: 'Beta', value: 'b' }] });`
312
- });
313
- await waitUntil(() => toolService.scriptAsks.has("ask-call"), { timeout: 1e4 });
314
- let ask = toolService.scriptAsks.get("ask-call");
315
- assert.strictEqual(ask.request.question, "Which one?");
316
- ask.answer("b");
317
- let result = await run;
318
- assert.deepEqual(JSON.parse(result.scriptResult), {
319
- answer: "b",
320
- label: "Beta"
321
- });
322
- assert.false(toolService.scriptAsks.has("ask-call"), "the answered question is gone");
323
- });
324
- (0, import_qunit.test)("Stop through the tool service withdraws the run's question", async function(assert) {
325
- let toolService = getService("tool-service");
326
- let command = new RunRealmCodeTool(toolService.toolContext);
327
- askThroughToolService(command, "stopped-ask-call");
328
- toolService.stoppableTools.set("stopped-ask-call", {
329
- roomId: "!room:example.com",
330
- stop: () => command.stop()
331
- });
332
- let run = command.execute({
333
- realm: testRealmURL,
334
- roomId: "!room:example.com",
335
- code: `await realm.ask({ question: 'Which one?', options: [{ label: 'A' }, { label: 'B' }] });
336
- return 'answered';`
337
- });
338
- await waitUntil(() => toolService.scriptAsks.has("stopped-ask-call"), { timeout: 1e4 });
339
- toolService.stopTool("stopped-ask-call");
340
- assert.false(toolService.scriptAsks.has("stopped-ask-call"), "the picker is withdrawn at once");
341
- await assert.rejects(run, /stopped|ended/i, "the run ends without an answer");
342
- });
343
- (0, import_qunit.test)("a question nobody answers ends the run when its wait runs out", async function(assert) {
344
- let toolService = getService("tool-service");
345
- toolService.__setWaitsForTesting({ scriptAskMaxMs: 50 });
346
- let command = new RunRealmCodeTool(toolService.toolContext);
347
- askThroughToolService(command, "unanswered-ask-call");
348
- let run = command.execute({
349
- realm: testRealmURL,
350
- roomId: "!room:example.com",
351
- code: `await realm.ask({ question: 'Which one?', options: [{ label: 'A' }, { label: 'B' }] });
352
- return 'answered';`
353
- });
354
- await assert.rejects(run, /No answer came within 50 ms/, "the run ends without an answer");
355
- assert.false(toolService.scriptAsks.has("unanswered-ask-call"), "the picker is withdrawn");
356
- });
357
- (0, import_qunit.test)("a run waiting on the reader's pick outlasts the tool deadline", async function(assert) {
358
- let toolService = getService("tool-service");
359
- let matrixService = getService("matrix-service");
360
- let deadlineMs = 500;
361
- toolService.__setWaitsForTesting({ toolExecuteTimeoutMs: deadlineMs });
362
- let results = [];
363
- let earlyFailures = [];
364
- let originalSend = matrixService.sendToolResultEvent;
365
- let originalUpdate = matrixService.updateSkillsAndToolsIfNeeded;
366
- let startedAt = 0;
367
- let askedAfterMs;
368
- let originalGetInputType = RunRealmCodeTool.prototype.getInputType;
369
- let originalExecute = RunRealmCodeTool.prototype.execute;
370
- RunRealmCodeTool.prototype.getInputType = async () => void 0;
371
- RunRealmCodeTool.prototype.execute = async function() {
372
- askedAfterMs = Date.now() - startedAt;
373
- await this.onAsk({
374
- question: "Which one?",
375
- kind: "options",
376
- allowOther: false,
377
- options: [{
378
- label: "A",
379
- value: "a"
380
- }, {
381
- label: "B",
382
- value: "b"
383
- }]
384
- });
385
- };
386
- matrixService.sendToolResultEvent = async (args) => {
387
- results.push({
388
- toolCallId: args.toolCallId,
389
- status: args.status
390
- });
391
- if (args.failureReason) earlyFailures.push(args.failureReason);
392
- };
393
- matrixService.updateSkillsAndToolsIfNeeded = async () => void 0;
394
- let running;
395
- try {
396
- let call = {
397
- id: "waiting-call",
398
- name: "runRealmCode",
399
- eventId: "$bot",
400
- message: { roomId: "!room:example.com" },
401
- codeRef: {
402
- module: "@cardstack/boxel-host/tools/run-realm-code",
403
- name: "default"
404
- },
405
- arguments: { attributes: {
406
- realm: testRealmURL,
407
- code: "ignored"
408
- } },
409
- isResolving: false,
410
- resolve: async () => void 0
411
- };
412
- startedAt = Date.now();
413
- running = toolService.run.perform(call, { auto: true });
414
- await waitUntil(() => toolService.scriptAsks.has("waiting-call"), { timeout: 1e4 });
415
- await new Promise((resolve) => setTimeout(resolve, startedAt + deadlineMs + 300 - Date.now()));
416
- assert.deepEqual(results, [], `the run is still waiting on the pick (asked ${askedAfterMs}ms into a ${deadlineMs}ms deadline; early results: ${earlyFailures.join("; ") || "none"})`);
417
- toolService.scriptAsks.get("waiting-call").answer("b");
418
- await running;
419
- assert.deepEqual(results, [{
420
- toolCallId: "waiting-call",
421
- status: "applied"
422
- }], `the run finishes with its answer instead of timing out (failures: ${earlyFailures.join("; ") || "none"})`);
423
- } finally {
424
- toolService.scriptAsks.get("waiting-call")?.cancel();
425
- await Promise.resolve(running).catch(() => void 0);
426
- RunRealmCodeTool.prototype.getInputType = originalGetInputType;
427
- RunRealmCodeTool.prototype.execute = originalExecute;
428
- matrixService.sendToolResultEvent = originalSend;
429
- matrixService.updateSkillsAndToolsIfNeeded = originalUpdate;
430
- }
431
- });
432
- (0, import_qunit.test)("the result attaches the files the run saved, then the captures it took", async function(assert) {
433
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
434
- let result = await command.execute({
435
- realm: testRealmURL,
436
- roomId: "!room:example.com",
437
- code: `await realm.fs.writeText('seen.json', '{}');
438
- return await realm.capture('seen.json');`
439
- });
440
- let attachments = command.resultAttachments(result);
441
- assert.deepEqual(attachments.map((file) => file.sourceUrl), [`${testRealmURL}seen.json`, result.captures[0].sourceUrl], "the saved file, then the capture");
442
- assert.strictEqual(attachments[0].url, void 0, "the saved file is uploaded from the realm when the result is sent");
443
- assert.strictEqual(attachments[1].url, result.captures[0].url, "the capture rides as the media already uploaded");
444
- assert.true(attachments[1].sourceUrl.startsWith(CAPTURE_SOURCE_URL_PREFIX), `the capture is named by a capture source URL, which keeps it out of correctness checks: ${attachments[1].sourceUrl}`);
445
- });
446
- (0, import_qunit.test)("an edit that lint takes back is reported as unchanged, not saved", async function(assert) {
447
- let toolService = getService("tool-service");
448
- let cardService = getService("card-service");
449
- let command = new RunRealmCodeTool(toolService.toolContext);
450
- let fileUrl = new URL(`${testRealmURL}tidy.gts`);
451
- let unusedImport = "\nimport NumberField from '@cardstack/base/number';";
452
- let passThrough = adapter.lintStub;
453
- adapter.lintStub = async (request) => ({
454
- output: (await request.text()).replace(unusedImport, ""),
455
- fixed: true,
456
- messages: []
457
- });
458
- await command.execute({
459
- realm: testRealmURL,
460
- roomId: "!room:example.com",
461
- code: `await realm.fs.writeText('tidy.gts', "import StringField from '@cardstack/base/string';\\nimport { CardDef, field, contains } from '@cardstack/base/card-api';\\n\\nexport class Tidy extends CardDef {\\n @field name = contains(StringField);\\n}\\n");`
462
- });
463
- let before = (await cardService.getSource(fileUrl)).content;
464
- let result = await command.execute({
465
- realm: testRealmURL,
466
- roomId: "!room:example.com",
467
- code: `await realm.fs.replace(
468
- 'tidy.gts',
469
- "import StringField from '@cardstack/base/string';",
470
- "import StringField from '@cardstack/base/string';\\nimport NumberField from '@cardstack/base/number';",
471
- );`
472
- });
473
- assert.deepEqual(result.files.map((file) => [file.fileUrl, file.status]), [[fileUrl.href, "unchanged"]]);
474
- assert.deepEqual(command.resultAttachments(result), [], "an unchanged file is not attached, so no correctness check runs on it");
475
- assert.strictEqual((await cardService.getSource(fileUrl)).content, before, "the file was not written");
476
- adapter.lintStub = passThrough;
477
- });
478
- (0, import_qunit.test)("opens the card the script returns to show", async function(assert) {
479
- let toolService = getService("tool-service");
480
- let operatorModeStateService = getService("operator-mode-state-service");
481
- operatorModeStateService.restore({
482
- stacks: [[]],
483
- submode: "interact"
484
- });
485
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
486
- realm: testRealmURL,
487
- roomId: "!room:example.com",
488
- code: `await realm.fs.writeText('Pet/biscuit.json', JSON.stringify({
489
- data: {
490
- attributes: { name: 'Biscuit' },
491
- meta: { adoptsFrom: { module: '../pet', name: 'Pet' } },
492
- },
493
- }));
494
- return { show: 'Pet/biscuit' };`
495
- });
496
- assert.strictEqual(result.files[0]?.status, "saved");
497
- assert.strictEqual(result.shownCard, `${testRealmURL}Pet/biscuit`);
498
- assert.notOk(result.showError);
499
- let shownIds = operatorModeStateService.state.stacks.flat().map((item) => item.id);
500
- assert.true(shownIds.includes(`${testRealmURL}Pet/biscuit`), "the card is open on a stack");
501
- });
502
- (0, import_qunit.test)("show opens a file that is not a card in code mode", async function(assert) {
503
- let toolService = getService("tool-service");
504
- let operatorModeStateService = getService("operator-mode-state-service");
505
- operatorModeStateService.restore({
506
- stacks: [[]],
507
- submode: "interact"
508
- });
509
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
510
- realm: testRealmURL,
511
- roomId: "!room:example.com",
512
- code: `return { show: 'notes/first.md' };`
513
- });
514
- assert.strictEqual(result.shownCard, `${testRealmURL}notes/first.md`);
515
- assert.notOk(result.showError);
516
- assert.strictEqual(operatorModeStateService.state.submode, "code");
517
- assert.strictEqual(operatorModeStateService.state.codePath, `${testRealmURL}notes/first.md`);
518
- });
519
- (0, import_qunit.test)("a card it cannot show does not fail the run", async function(assert) {
520
- let toolService = getService("tool-service");
521
- let operatorModeStateService = getService("operator-mode-state-service");
522
- operatorModeStateService.restore({
523
- stacks: [[]],
524
- submode: "interact"
525
- });
526
- let command = new RunRealmCodeTool(toolService.toolContext);
527
- let result = await command.execute({
528
- realm: testRealmURL,
529
- roomId: "!room:example.com",
530
- code: `await realm.fs.writeText('seen.json', '{}');
531
- return { show: 'Pet/missing' };`
532
- });
533
- assert.strictEqual(result.files[0]?.status, "saved", "files still report");
534
- assert.notOk(result.shownCard);
535
- assert.true(/Not found: .*Pet\/missing/.test(result.showError ?? ""), `says why: ${result.showError}`);
536
- let outside = await command.execute({
537
- realm: testRealmURL,
538
- roomId: "!room:example.com",
539
- code: `return { show: 'https://example.com/card' };`
540
- });
541
- assert.true(/Path is outside this realm/.test(outside.showError ?? ""), `refuses another realm: ${outside.showError}`);
542
- assert.deepEqual(operatorModeStateService.state.stacks.flat(), [], "nothing is opened");
543
- });
544
- (0, import_qunit.test)("realm.capture refuses a fourth capture in one run", async function(assert) {
545
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
546
- await assert.rejects(command.execute({
547
- realm: testRealmURL,
548
- roomId: "!room:example.com",
549
- code: `for (let i = 0; i < 4; i++) { await realm.capture('task.json'); }`
550
- }), /realm\.capture may run at most 3 times in one run/);
551
- assert.strictEqual(captureRequests.length, 3, "three captures were taken");
552
- });
553
- (0, import_qunit.test)("realm.capture captures a card by its path or its id, with the options it is given", async function(assert) {
554
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
555
- realm: testRealmURL,
556
- roomId: "!room:example.com",
557
- code: `return [
558
- await realm.capture('Pet/mango'),
559
- await realm.capture('${testRealmURL}Pet/mango', {
560
- format: 'embedded',
561
- viewportWidth: 600,
562
- viewportHeight: 400,
563
- target: '.name',
564
- }),
565
- ];`
566
- });
567
- assert.strictEqual(captureRequests.length, 2, "two capture requests");
568
- let [byPath, byId] = captureRequests.map((r) => r.data.attributes);
569
- assert.strictEqual(byPath.cardId, `${testRealmURL}Pet/mango`);
570
- assert.strictEqual(byId.cardId, `${testRealmURL}Pet/mango`);
571
- assert.strictEqual(byId.format, "embedded");
572
- assert.deepEqual(byId.captureSpec, {
573
- viewport: {
574
- width: 600,
575
- height: 400
576
- },
577
- target: ".name"
578
- });
579
- let [first, second] = JSON.parse(result.scriptResult);
580
- assert.strictEqual(first.path, "Pet/mango");
581
- assert.strictEqual(first.kind, "card");
582
- assert.strictEqual(second.path, "Pet/mango", "a URL in the run realm is named by its path");
583
- assert.strictEqual(second.format, "embedded");
584
- assert.strictEqual(second.viewportWidth, 600);
585
- assert.strictEqual(second.viewportHeight, 400);
586
- assert.strictEqual(second.target, ".name");
587
- assert.strictEqual(first.target, void 0, "a page capture has none");
588
- assert.strictEqual(result.captures.length, 2);
589
- });
590
- (0, import_qunit.test)("realm.capture refuses a URL outside every workspace", async function(assert) {
591
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
592
- await assert.rejects(command.execute({
593
- realm: testRealmURL,
594
- roomId: "!room:example.com",
595
- code: `await realm.capture('https://example.com/page.html');`
596
- }), /not in a workspace the user can read/);
597
- assert.strictEqual(captureRequests.length, 0, "no capture is attempted");
598
- });
599
- (0, import_qunit.test)("realm.capture refuses a file attached to the chat, and says how to see it again", async function(assert) {
600
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
601
- let attachment = `${LOCAL_SOURCE_URL_PREFIX}00000000-0000-4000-8000-000000000001/photo.jpg`;
602
- await assert.rejects(command.execute({
603
- realm: testRealmURL,
604
- roomId: "!room:example.com",
605
- code: `return await realm.capture('${attachment}');`
606
- }), (error) => error.message.includes(`Cannot capture ${attachment}`) && error.message.includes("attach it again"));
607
- assert.strictEqual(captureRequests.length, 0, "no capture is attempted");
608
- });
609
- (0, import_qunit.test)("realm.capture refuses the image a capture took, and says to capture what it shows", async function(assert) {
610
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
611
- let captured = `${CAPTURE_SOURCE_URL_PREFIX}0000000000000001/mango.png`;
612
- await assert.rejects(command.execute({
613
- realm: testRealmURL,
614
- roomId: "!room:example.com",
615
- code: `return await realm.capture('${captured}');`
616
- }), (error) => error.message.includes(`Cannot capture ${captured}`) && error.message.includes("capture the card or file it shows") && !error.message.includes("attach it again"));
617
- assert.strictEqual(captureRequests.length, 0, "no capture is attempted");
618
- });
619
- (0, import_qunit.test)("the description says realm.capture refuses a file attached to the chat", async function(assert) {
620
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
621
- assert.true(command.description.includes(`a ${LOCAL_SOURCE_URL_PREFIX} URL`), "the description names the prefix of a file attached from the computer");
622
- assert.true(command.description.includes("so realm.capture refuses it"), "a model choosing a capture target reads that such a file is not one");
623
- });
624
- (0, import_qunit.test)("realm.capture finds the workspace of a prefixed id, whatever form the workspace is known by", async function(assert) {
625
- let { virtualNetwork } = getService("network");
626
- virtualNetwork.addRealmMapping("@test/mapped/", "http://test-realm/mapped/");
627
- try {
628
- knowReadableWorkspace("@test/mapped/");
629
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
630
- realm: testRealmURL,
631
- roomId: "!room:example.com",
632
- code: `return await realm.capture('@test/mapped/Pet/mango');`
633
- });
634
- assert.strictEqual(captureRequests.length, 1, "one capture request");
635
- let { realmURL, cardId } = captureRequests[0].data.attributes;
636
- assert.strictEqual(realmURL, "http://test-realm/mapped/");
637
- assert.strictEqual(cardId, "http://test-realm/mapped/Pet/mango");
638
- assert.strictEqual(JSON.parse(result.scriptResult).path, "@test/mapped/Pet/mango", "the capture is named by the id the script gave");
639
- } finally {
640
- virtualNetwork.removeRealmMapping("@test/mapped/");
641
- }
642
- });
643
- (0, import_qunit.test)("realm.capture asks a workspace nested under the run realm for its own card, and names it by its URL", async function(assert) {
644
- let nestedRealmURL = `${testRealmURL}nested/`;
645
- knowReadableWorkspace(nestedRealmURL);
646
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
647
- realm: testRealmURL,
648
- roomId: "!room:example.com",
649
- code: `return [
650
- await realm.capture('${nestedRealmURL}Pet/mango'),
651
- await realm.capture('${testRealmURL}Pet/mango'),
652
- ];`
653
- });
654
- assert.deepEqual(captureRequests.map((r) => r.data.attributes.realmURL), [nestedRealmURL, testRealmURL], "each capture is asked of the deepest workspace that holds it");
655
- let [nested, own] = JSON.parse(result.scriptResult);
656
- assert.strictEqual(nested.path, `${nestedRealmURL}Pet/mango`, "a card in the nested workspace keeps its URL");
657
- assert.strictEqual(own.path, "Pet/mango");
658
- });
659
- (0, import_qunit.test)("realm.cards.get returns a card as data, with computed fields and absolute URLs", async function(assert) {
660
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
661
- let result = await command.execute({
662
- realm: testRealmURL,
663
- roomId: "!room:example.com",
664
- code: `return {
665
- bare: await realm.cards.get('people/hassan'),
666
- withExtension: await realm.cards.get('people/hassan.json'),
667
- byURL: await realm.cards.get(${JSON.stringify(`${testRealmURL}people/hassan`)}),
668
- };`
669
- });
670
- assert.deepEqual(result.files, [], "reading a card saves nothing");
671
- let { bare, withExtension, byURL } = JSON.parse(result.scriptResult);
672
- assert.strictEqual(bare.path, "people/hassan.json");
673
- assert.strictEqual(bare.id, `${testRealmURL}people/hassan`);
674
- assert.deepEqual(bare.type, {
675
- module: `${testRealmURL}person`,
676
- name: "Person"
677
- });
678
- assert.strictEqual(bare.attributes.firstName, "Hassan");
679
- assert.strictEqual(bare.attributes.cardTitle, "Hassan", "computed fields are included");
680
- assert.deepEqual(bare.relationships, { friend: `${testRealmURL}people/mango` }, "links are keyed by field path, as realm.cards.search returns them");
681
- assert.deepEqual(withExtension, bare, "a .json path reads the same card");
682
- assert.deepEqual(byURL, bare, "a URL reads the same card");
683
- let afterEdit = await command.execute({
684
- realm: testRealmURL,
685
- roomId: "!room:example.com",
686
- code: `await realm.cards.get('people/hassan');
687
- await realm.fs.replace('people/hassan.json', '"Hassan"', '"Hassan Abdel"');
688
- return await realm.cards.get('people/hassan');`
689
- });
690
- assert.strictEqual(JSON.parse(afterEdit.scriptResult).attributes.firstName, "Hassan Abdel", "a card read after an edit in the same run shows the edit");
691
- await assert.rejects(command.execute({
692
- realm: testRealmURL,
693
- roomId: "!room:example.com",
694
- code: `await realm.cards.get('people/missing');`
695
- }), /Card not found/);
696
- await assert.rejects(command.execute({
697
- realm: testRealmURL,
698
- roomId: "!room:example.com",
699
- code: `await realm.cards.get('https://example.com/card');`
700
- }), /Path is outside this realm/);
701
- });
702
- (0, import_qunit.test)("realm.cards.get says to read a card that is not indexed again only while the workspace is indexing, and names the call that indexes it otherwise", async function(assert) {
703
- await adapter.write("Pet/unindexed.json", UNINDEXED_PET);
704
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
705
- let messageService = getService("message-service");
706
- messageService.relayRealmEvent({
707
- eventName: "index",
708
- indexType: "incremental-index-initiation",
709
- updatedFile: `${testRealmURL}task.json`,
710
- realmURL: testRealmURL
711
- });
712
- let whileIndexing;
713
- try {
714
- whileIndexing = await command.execute({
715
- realm: testRealmURL,
716
- roomId: "!room:example.com",
717
- code: readCardScript("Pet/unindexed")
718
- });
719
- } finally {
720
- messageService.relayRealmEvent({
721
- eventName: "index",
722
- indexType: "incremental",
723
- invalidations: [],
724
- realmURL: testRealmURL
725
- });
726
- }
727
- assert.strictEqual(JSON.parse(whileIndexing.scriptResult), `Card is not indexed yet: ${testRealmURL}Pet/unindexed; read it again in a moment. If it is still not indexed after a few reads, index the file with realm.index.invalidate('Pet/unindexed.json')`, "while a pass runs, the row may still come, so the card is read again");
728
- let idle = await command.execute({
729
- realm: testRealmURL,
730
- roomId: "!room:example.com",
731
- code: readCardScript("Pet/unindexed.json")
732
- });
733
- assert.strictEqual(JSON.parse(idle.scriptResult), `Card is not indexed: ${testRealmURL}Pet/unindexed. Its file Pet/unindexed.json is in the workspace, and the workspace is not indexing, so reading the card again will not find it. Index the file with realm.index.invalidate('Pet/unindexed.json'), then read the card again. Do not edit the card to make the workspace index it`, "with no pass running, the error names the call that indexes the file");
734
- let recovered = await command.execute({
735
- realm: testRealmURL,
736
- roomId: "!room:example.com",
737
- code: `await realm.index.invalidate('Pet/unindexed.json');
738
- return await realm.cards.get('Pet/unindexed');`
739
- });
740
- assert.strictEqual(JSON.parse(recovered.scriptResult).attributes.name, "Biscuit", "the call the error names indexes the card, and the card reads");
741
- assert.deepEqual(recovered.files, [], "no file was edited to get there");
742
- });
743
- (0, import_qunit.test)("realm.cards.get names the error of a card that failed to index", async function(assert) {
744
- await testRealm.write("Pet/orphan.json", JSON.stringify({ data: {
745
- type: "card",
746
- attributes: { name: "Orphan" },
747
- meta: { adoptsFrom: {
748
- module: "../no-such-module",
749
- name: "Pet"
750
- } }
751
- } }));
752
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
753
- realm: testRealmURL,
754
- roomId: "!room:example.com",
755
- code: readCardScript("Pet/orphan")
756
- });
757
- let message = JSON.parse(result.scriptResult);
758
- assert.true(message.startsWith(`Card failed to index: ${testRealmURL}Pet/orphan: `), message);
759
- assert.true(/no-such-module/.test(message), `the index error's own text is in the message: ${message}`);
760
- assert.true(message.endsWith("Reading it again gives the same error until its cause is fixed, in Pet/orphan.json, in the definition it adopts from, or in a card it links to"), message);
761
- });
762
- (0, import_qunit.test)("realm.cards.get says a path that names a file is not a card", async function(assert) {
763
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
764
- realm: testRealmURL,
765
- roomId: "!room:example.com",
766
- code: `let messages = [];
767
- for (let path of ['images/existing.png', 'notes/first.md']) {
768
- try { await realm.cards.get(path); } catch (e) { messages.push(e.message); }
769
- }
770
- return messages;`
771
- });
772
- assert.deepEqual(JSON.parse(result.scriptResult), ["Not a card: images/existing.png is a file, so realm.cards.get cannot read it; read it with realm.fs.readText if it is text, or look at it with realm.capture", "Not a card: notes/first.md is a file, so realm.cards.get cannot read it; read it with realm.fs.readText if it is text, or look at it with realm.capture"]);
773
- });
774
- (0, import_qunit.test)("realm.cards.get does not blame the card for a read that failed for another reason", async function(assert) {
775
- let cardURL = `${testRealmURL}Pet/mango`;
776
- let cardService = getService("card-service");
777
- let originalFetchJSON = cardService.fetchJSON.bind(cardService);
778
- cardService.fetchJSON = async (url, args) => {
779
- if (String(url) === cardURL) {
780
- let err = /* @__PURE__ */ new Error("realm failure");
781
- err.status = 500;
782
- err.responseText = JSON.stringify({ errors: [{
783
- id: cardURL,
784
- status: 500,
785
- title: "Internal Server Error",
786
- message: "the database is unavailable"
787
- }] });
788
- throw err;
789
- }
790
- return originalFetchJSON(url, args);
791
- };
792
- let result;
793
- try {
794
- result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
795
- realm: testRealmURL,
796
- roomId: "!room:example.com",
797
- code: readCardScript("Pet/mango")
798
- });
799
- } finally {
800
- delete cardService.fetchJSON;
801
- }
802
- assert.strictEqual(JSON.parse(result.scriptResult), `Unable to read card ${cardURL}: the database is unavailable`);
803
- });
804
- (0, import_qunit.test)("the tool description names the call that indexes a card that is not indexed, and rules out editing the card for it", function(assert) {
805
- let { description } = new RunRealmCodeTool(getService("tool-service").toolContext);
806
- assert.true(description.includes("realm.index.invalidate('<card path>.json')"), description);
807
- assert.true(description.includes("never edit a card's data to make the workspace index it"), description);
808
- });
809
- (0, import_qunit.test)("replays a replacement against the source that was read", async function(assert) {
810
- let toolService = getService("tool-service");
811
- let cardService = getService("card-service");
812
- let command = new RunRealmCodeTool(toolService.toolContext);
813
- let fileUrl = `${testRealmURL}task.json`;
814
- let result = await command.execute({
815
- realm: testRealmURL,
816
- roomId: "!room:example.com",
817
- code: `await realm.fs.replace(${JSON.stringify(fileUrl)}, '"Old title"', '"New title"');`
818
- });
819
- assert.strictEqual(result.files[0]?.status, "saved");
820
- let source = await cardService.getSource(new URL(fileUrl));
821
- assert.strictEqual(source.content, `{
822
- "title": "New title",
823
- "count": 1
824
- }
825
- `);
826
- });
827
- (0, import_qunit.test)("creates a declared source file", async function(assert) {
828
- let toolService = getService("tool-service");
829
- let cardService = getService("card-service");
830
- let command = new RunRealmCodeTool(toolService.toolContext);
831
- let fileUrl = `${testRealmURL}new-task.json`;
832
- let result = await command.execute({
833
- realm: testRealmURL,
834
- roomId: "!room:example.com",
835
- code: `await realm.fs.writeText(${JSON.stringify(fileUrl)}, '{\\n "title": "New task"\\n}\\n');`
836
- });
837
- assert.strictEqual(result.files[0]?.status, "saved");
838
- let source = await cardService.getSource(new URL(fileUrl));
839
- assert.strictEqual(source.status, 200);
840
- assert.strictEqual(source.content, "{\n \"title\": \"New task\"\n}\n");
841
- });
842
- (0, import_qunit.test)("realm.fs.writeBytes saves the decoded bytes of a new binary file", async function(assert) {
843
- let toolService = getService("tool-service");
844
- let network = getService("network");
845
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
846
- realm: testRealmURL,
847
- roomId: "!room:example.com",
848
- code: `let saved = await realm.fs.writeBytes('images/dot.png', ${JSON.stringify(PNG_BASE64)});
849
- return { saved, exists: await realm.fs.exists('images/dot.png') };`
850
- });
851
- let expected = Uint8Array.from(atob(PNG_BASE64), (char) => char.charCodeAt(0));
852
- assert.deepEqual(JSON.parse(result.scriptResult), {
853
- saved: {
854
- path: "images/dot.png",
855
- size: expected.byteLength,
856
- saved: true
857
- },
858
- exists: true
859
- });
860
- assert.deepEqual(result.files.map((file) => [
861
- file.fileUrl,
862
- file.status,
863
- file.detail
864
- ]), [[
865
- `${testRealmURL}images/dot.png`,
866
- "saved",
867
- "Binary file saved."
868
- ]]);
869
- let response = await network.authedFetch(new URL("images/dot.png", testRealmURL));
870
- assert.strictEqual(response.status, 200);
871
- assert.deepEqual(Array.from(new Uint8Array(await response.arrayBuffer())), Array.from(expected), "the realm holds the decoded bytes");
872
- });
873
- (0, import_qunit.test)("realm.fs.writeBytes accepts a base64 data URL", async function(assert) {
874
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
875
- realm: testRealmURL,
876
- roomId: "!room:example.com",
877
- code: `return await realm.fs.writeBytes('dot.png', ${JSON.stringify(`data:image/png;base64,${PNG_BASE64}`)});`
878
- });
879
- assert.true(JSON.parse(result.scriptResult).saved);
880
- });
881
- (0, import_qunit.test)("realm.fs.writeBytes refuses a file that exists, and content that is not base64", async function(assert) {
882
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
883
- await assert.rejects(command.execute({
884
- realm: testRealmURL,
885
- roomId: "!room:example.com",
886
- code: `await realm.fs.writeBytes('task.json', ${JSON.stringify(PNG_BASE64)});`
887
- }), /File already exists/, "refuses an existing text file");
888
- await command.execute({
889
- realm: testRealmURL,
890
- roomId: "!room:example.com",
891
- code: `await realm.fs.writeBytes('dot.png', ${JSON.stringify(PNG_BASE64)});`
892
- });
893
- await assert.rejects(command.execute({
894
- realm: testRealmURL,
895
- roomId: "!room:example.com",
896
- code: `await realm.fs.writeBytes('dot.png', ${JSON.stringify(PNG_BASE64)});`
897
- }), /File already exists/, "refuses an existing binary file");
898
- await assert.rejects(command.execute({
899
- realm: testRealmURL,
900
- roomId: "!room:example.com",
901
- code: `await realm.fs.writeBytes('bad.png', 'not base64!');`
902
- }), /not valid base64/);
903
- await assert.rejects(command.execute({
904
- realm: testRealmURL,
905
- roomId: "!room:example.com",
906
- code: `await realm.fs.readText('dot.png');`
907
- }), /is a binary file/, "readText names a binary file instead of failing on its status");
908
- await command.execute({
909
- realm: testRealmURL,
910
- roomId: "!room:example.com",
911
- code: `await realm.fs.writeBytes('report.xlsx', ${JSON.stringify(PNG_BASE64)});`
912
- });
913
- await assert.rejects(command.execute({
914
- realm: testRealmURL,
915
- roomId: "!room:example.com",
916
- code: `await realm.fs.replace('report.xlsx', 'a', 'b');`
917
- }), /is a binary file/, "replace refuses a vendor binary type");
918
- });
919
- (0, import_qunit.test)("realm.fs.writeBytes refuses a file over the size limit", async function(assert) {
920
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
921
- await assert.rejects(command.execute({
922
- realm: testRealmURL,
923
- roomId: "!room:example.com",
924
- code: `await realm.fs.writeBytes('big.bin', 'AAAA'.repeat(700000));`
925
- }), /at most 2000000 bytes per file.*No file was saved/);
926
- });
927
- (0, import_qunit.test)("realm.fs.delete deletes a file the same run created, and the result reports it", async function(assert) {
928
- let toolService = getService("tool-service");
929
- let cardService = getService("card-service");
930
- let command = new RunRealmCodeTool(toolService.toolContext);
931
- let result = await command.execute({
932
- realm: testRealmURL,
933
- roomId: "!room:example.com",
934
- code: `await realm.fs.writeText('plan.md', '# Plan\\n');
935
- await realm.fs.writeText('kept.md', '# Kept\\n');
936
- await realm.fs.writeBytes('dot.png', ${JSON.stringify(PNG_BASE64)});
937
- let deleted = [
938
- await realm.fs.delete('plan.md'),
939
- await realm.fs.delete('dot.png'),
940
- ];
941
- return {
942
- deleted,
943
- planExists: await realm.fs.exists('plan.md'),
944
- dotExists: await realm.fs.exists('dot.png'),
945
- };`
946
- });
947
- assert.deepEqual(JSON.parse(result.scriptResult), {
948
- deleted: [{
949
- path: "plan.md",
950
- deleted: true
951
- }, {
952
- path: "dot.png",
953
- deleted: true
954
- }],
955
- planExists: false,
956
- dotExists: false
957
- });
958
- assert.deepEqual(result.files.map((file) => [file.fileUrl, file.status]), [
959
- [`${testRealmURL}kept.md`, "saved"],
960
- [`${testRealmURL}plan.md`, "deleted"],
961
- [`${testRealmURL}dot.png`, "deleted"]
962
- ]);
963
- assert.deepEqual(command.resultAttachments(result).map((attachment) => attachment.sourceUrl), [`${testRealmURL}kept.md`], "a deleted file is not attached to the result");
964
- for (let path of ["plan.md", "dot.png"]) {
965
- let source = await cardService.getSource(new URL(path, testRealmURL));
966
- assert.strictEqual(source.status, 404, `${path} is not in the realm`);
967
- }
968
- });
969
- (0, import_qunit.test)("realm.fs.delete refuses a binary file the run created when someone replaced it", async function(assert) {
970
- let toolService = getService("tool-service");
971
- let network = getService("network");
972
- let command = new RunRealmCodeTool(toolService.toolContext);
973
- let dotURL = `${testRealmURL}dot.png`;
974
- let replacement = Uint8Array.from([
975
- 137,
976
- 80,
977
- 78,
978
- 71,
979
- 255,
980
- 254
981
- ]);
982
- let real = network.authedFetch;
983
- Object.defineProperty(network, "authedFetch", {
984
- configurable: true,
985
- value: async (url, init) => {
986
- let response = await real(url, init);
987
- if (url === dotURL && init?.method === "POST" && response.ok) {
988
- let replaced = await real(dotURL, {
989
- method: "POST",
990
- headers: { "Content-Type": "application/octet-stream" },
991
- body: new Blob([replacement])
992
- });
993
- assert.true(replaced.ok, "the collaborator replaced the file");
994
- }
995
- return response;
996
- }
997
- });
998
- let result = await command.execute({
999
- realm: testRealmURL,
1000
- roomId: "!room:example.com",
1001
- code: `await realm.fs.writeBytes('dot.png', ${JSON.stringify(PNG_BASE64)});
1002
- try {
1003
- await realm.fs.delete('dot.png');
1004
- return 'deleted';
1005
- } catch (e) {
1006
- return e.message;
1007
- }`
1008
- });
1009
- assert.true(/File changed while the script ran: .*dot\.png/.test(JSON.parse(result.scriptResult)), `the delete is refused: ${result.scriptResult}`);
1010
- let response = await real(dotURL, { headers: { Accept: SupportedMimeType.CardSource } });
1011
- assert.strictEqual(response.status, 200, "dot.png is still in the realm");
1012
- assert.deepEqual(Array.from(new Uint8Array(await response.arrayBuffer())), Array.from(replacement), "the collaborator's bytes are kept");
1013
- });
1014
- (0, import_qunit.test)("a script that deletes a file always waits for the user", function(assert) {
1015
- assert.true(RunRealmCodeTool.neverAutoExecutesFor({ code: `await realm.fs.delete('notes/first.md');` }), "a run that names realm.fs.delete waits for a click");
1016
- assert.true(RunRealmCodeTool.neverAutoExecutesFor({ code: `await realm.fs.writeText('a.md', 'x'); await realm.fs.delete('a.md');` }), "a run that deletes only its own file also waits for a click");
1017
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code: `await realm.fs.writeText('a.md', 'x');` }), "a run that deletes nothing keeps the room mode");
1018
- });
1019
- (0, import_qunit.test)("realm.fs.delete deletes files that were there before the run, and the result reports them", async function(assert) {
1020
- let toolService = getService("tool-service");
1021
- let cardService = getService("card-service");
1022
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
1023
- realm: testRealmURL,
1024
- roomId: "!room:example.com",
1025
- code: `await realm.fs.readText('notes/first.md');
1026
- await realm.fs.replace('task.json', '"Old title"', '"New title"');
1027
- await realm.fs.writeText('plan.md', '# Plan\\n');
1028
- let deleted = [
1029
- await realm.fs.delete('notes/first.md'),
1030
- await realm.fs.delete('task.json'),
1031
- await realm.fs.delete('images/existing.png'),
1032
- await realm.fs.delete('plan.md'),
1033
- ];
1034
- let refused = [];
1035
- try { await realm.fs.delete('notes/first.md'); } catch (e) { refused.push(e.message); }
1036
- try { await realm.fs.delete('missing.md'); } catch (e) { refused.push(e.message); }
1037
- try { await realm.fs.delete('notes/'); } catch (e) { refused.push(e.message); }
1038
- return { deleted, refused };`
1039
- });
1040
- let { deleted, refused } = JSON.parse(result.scriptResult);
1041
- assert.deepEqual(deleted, [
1042
- {
1043
- path: "notes/first.md",
1044
- deleted: true
1045
- },
1046
- {
1047
- path: "task.json",
1048
- deleted: true
1049
- },
1050
- {
1051
- path: "images/existing.png",
1052
- deleted: true
1053
- },
1054
- {
1055
- path: "plan.md",
1056
- deleted: true
1057
- }
1058
- ]);
1059
- assert.true(/this run already deleted it: .*notes\/first\.md/.test(refused[0]), `a file the run already deleted: ${refused[0]}`);
1060
- assert.true(/File not found: .*missing\.md/.test(refused[1]), `a file that does not exist: ${refused[1]}`);
1061
- assert.true(/Path must be relative to the realm root: notes\//.test(refused[2]), `a folder: ${refused[2]}`);
1062
- assert.deepEqual(result.files.map((file) => [
1063
- file.fileUrl,
1064
- file.status,
1065
- file.detail
1066
- ]), [
1067
- [
1068
- `${testRealmURL}plan.md`,
1069
- "deleted",
1070
- "Created by this run and then deleted."
1071
- ],
1072
- [
1073
- `${testRealmURL}notes/first.md`,
1074
- "deleted",
1075
- "Existed before this run; deleted."
1076
- ],
1077
- [
1078
- `${testRealmURL}task.json`,
1079
- "deleted",
1080
- "Existed before this run; deleted."
1081
- ],
1082
- [
1083
- `${testRealmURL}images/existing.png`,
1084
- "deleted",
1085
- "Existed before this run; deleted."
1086
- ]
1087
- ]);
1088
- for (let path of [
1089
- "notes/first.md",
1090
- "task.json",
1091
- "images/existing.png"
1092
- ]) {
1093
- let source = await cardService.getSource(new URL(path, testRealmURL));
1094
- assert.strictEqual(source.status, 404, `${path} is not in the realm`);
1095
- }
1096
- });
1097
- (0, import_qunit.test)("realm.fs.delete refuses a file someone changed after the script read it", async function(assert) {
1098
- let toolService = getService("tool-service");
1099
- let cardService = getService("card-service");
1100
- let network = getService("network");
1101
- let command = new RunRealmCodeTool(toolService.toolContext);
1102
- let noteURL = `${testRealmURL}notes/first.md`;
1103
- let real = network.authedFetch;
1104
- let changed = false;
1105
- Object.defineProperty(network, "authedFetch", {
1106
- configurable: true,
1107
- value: async (url, init) => {
1108
- let response = await real(url, init);
1109
- if (url === noteURL && !init?.method && !changed) {
1110
- changed = true;
1111
- let replaced = await real(noteURL, {
1112
- method: "POST",
1113
- headers: { "Content-Type": "application/octet-stream" },
1114
- body: new Blob(["# Changed\n"])
1115
- });
1116
- assert.true(replaced.ok, "the collaborator changed the file");
1117
- }
1118
- return response;
1119
- }
1120
- });
1121
- let result = await command.execute({
1122
- realm: testRealmURL,
1123
- roomId: "!room:example.com",
1124
- code: `await realm.fs.readText('notes/first.md');
1125
- try {
1126
- await realm.fs.delete('notes/first.md');
1127
- return 'deleted';
1128
- } catch (e) {
1129
- return e.message;
1130
- }`
1131
- });
1132
- assert.true(/File changed while the script ran: .*notes\/first\.md/.test(JSON.parse(result.scriptResult)), `the delete is refused: ${result.scriptResult}`);
1133
- let source = await cardService.getSource(new URL(noteURL));
1134
- assert.strictEqual(source.status, 200, "the file is still in the realm");
1135
- assert.strictEqual(source.content, "# Changed\n", "the change is kept");
1136
- });
1137
- (0, import_qunit.test)("a script that reaches realm.fs.delete another way is refused", async function(assert) {
1138
- let cardService = getService("card-service");
1139
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1140
- let code = `await realm.fs['de' + 'lete']('notes/first.md');`;
1141
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code }), "this run would not wait for a click");
1142
- await assert.rejects(command.execute({
1143
- realm: testRealmURL,
1144
- roomId: "!room:example.com",
1145
- code
1146
- }), /must be called by that name/);
1147
- let source = await cardService.getSource(new URL("notes/first.md", testRealmURL));
1148
- assert.strictEqual(source.status, 200, "the file is still in the realm");
1149
- });
1150
- (0, import_qunit.test)("a failed run names the files from before the run that it deleted", async function(assert) {
1151
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1152
- await assert.rejects(command.execute({
1153
- realm: testRealmURL,
1154
- roomId: "!room:example.com",
1155
- code: `await realm.fs.delete('notes/first.md');
1156
- await realm.fs.readText('missing.md');`
1157
- }), /Files that existed before this run and that it already deleted: .*notes\/first\.md/);
1158
- });
1159
- (0, import_qunit.test)("a failed run names the files it created and deleted", async function(assert) {
1160
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1161
- await assert.rejects(command.execute({
1162
- realm: testRealmURL,
1163
- roomId: "!room:example.com",
1164
- code: `await realm.fs.writeText('plan.md', 'x');
1165
- await realm.fs.delete('plan.md');
1166
- await realm.fs.readText('missing.md');`
1167
- }), /No file was saved\. Files this run created and already deleted: .*plan\.md/);
1168
- });
1169
- (0, import_qunit.test)("realm.fs.copy copies a file and leaves the source as it was", async function(assert) {
1170
- let toolService = getService("tool-service");
1171
- let cardService = getService("card-service");
1172
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
1173
- realm: testRealmURL,
1174
- roomId: "!room:example.com",
1175
- code: `return await realm.fs.copy('notes/first.md', 'notes/second.md');`
1176
- });
1177
- assert.deepEqual(JSON.parse(result.scriptResult), {
1178
- path: "notes/second.md",
1179
- saved: true
1180
- });
1181
- assert.deepEqual(result.files.map((file) => [file?.fileUrl, file?.status]), [[`${testRealmURL}notes/second.md`, "saved"]]);
1182
- let copy = await cardService.getSource(new URL(`${testRealmURL}notes/second.md`));
1183
- assert.strictEqual(copy.content, "# First\n");
1184
- let source = await cardService.getSource(new URL(`${testRealmURL}notes/first.md`));
1185
- assert.strictEqual(source.content, "# First\n", "the source is unchanged");
1186
- });
1187
- (0, import_qunit.test)("realm.fs.copy of a card instance in the same folder loads as the same card type", async function(assert) {
1188
- let toolService = getService("tool-service");
1189
- let store = getService("store");
1190
- await new RunRealmCodeTool(toolService.toolContext).execute({
1191
- realm: testRealmURL,
1192
- roomId: "!room:example.com",
1193
- code: `await realm.fs.copy('Pet/mango.json', 'Pet/mango-copy.json');
1194
- await realm.fs.replace('Pet/mango-copy.json', '"Mango"', '"Mango Two"');`
1195
- });
1196
- let copy = await store.get(`${testRealmURL}Pet/mango-copy`);
1197
- assert.strictEqual(copy.constructor.displayName, "Pet");
1198
- assert.strictEqual(copy.name, "Mango Two");
1199
- });
1200
- (0, import_qunit.test)("realm.fs.copy refuses an existing target, a missing source, and paths outside the realm", async function(assert) {
1201
- let toolService = getService("tool-service");
1202
- let cardService = getService("card-service");
1203
- let command = new RunRealmCodeTool(toolService.toolContext);
1204
- let run = (code) => command.execute({
1205
- realm: testRealmURL,
1206
- roomId: "!room:example.com",
1207
- code
1208
- });
1209
- await assert.rejects(run(`await realm.fs.copy('notes/first.md', 'task.json');`), /File already exists: .*task\.json/);
1210
- let target = await cardService.getSource(new URL(`${testRealmURL}task.json`));
1211
- assert.true(target.content.includes("\"Old title\""), "the existing target is unchanged");
1212
- await assert.rejects(run(`await realm.fs.copy('nope.md', 'copy.md');`), /File not found: .*nope\.md/);
1213
- await assert.rejects(run(`await realm.fs.copy('notes/first.md', '../elsewhere.md');`), /Path must be relative to the realm root/);
1214
- await assert.rejects(run(`await realm.fs.copy('https://example.com/other/first.md', 'copy.md');`), /Path is outside this realm/);
1215
- });
1216
- (0, import_qunit.test)("realm.fs.copy refuses files that are not UTF-8 text", async function(assert) {
1217
- let toolService = getService("tool-service");
1218
- let cardService = getService("card-service");
1219
- let command = new RunRealmCodeTool(toolService.toolContext);
1220
- for (let [from, to] of [
1221
- ["images/existing.png", "images/existing-copy.png"],
1222
- ["docs/report.docx", "docs/report-copy.docx"],
1223
- ["docs/latin1.txt", "docs/latin1-copy.txt"]
1224
- ]) {
1225
- await assert.rejects(command.execute({
1226
- realm: testRealmURL,
1227
- roomId: "!room:example.com",
1228
- code: `await realm.fs.copy('${from}', '${to}');`
1229
- }), /is a binary file/, `refuses ${from}`);
1230
- let copy = await cardService.getSource(new URL(`${testRealmURL}${to}`));
1231
- assert.strictEqual(copy.status, 404, `no copy of ${from} is saved`);
1232
- }
1233
- });
1234
- (0, import_qunit.test)("realm.fs.copy copies UTF-8 text byte for byte, whatever its content type", async function(assert) {
1235
- let toolService = getService("tool-service");
1236
- let network = getService("network");
1237
- let command = new RunRealmCodeTool(toolService.toolContext);
1238
- let bytesOf = async (path) => {
1239
- let response = await network.authedFetch(`${testRealmURL}${path}`, { headers: { Accept: "application/vnd.card+source" } });
1240
- return Array.from(new Uint8Array(await response.arrayBuffer()));
1241
- };
1242
- await command.execute({
1243
- realm: testRealmURL,
1244
- roomId: "!room:example.com",
1245
- code: `await realm.fs.copy('docs/README', 'docs/README-copy');
1246
- await realm.fs.copy('docs/replacement.txt', 'docs/replacement-copy.txt');
1247
- await realm.fs.copy('unformatted.gts', 'unformatted-copy.gts');`
1248
- });
1249
- for (let path of [
1250
- "docs/README",
1251
- "docs/replacement.txt",
1252
- "unformatted.gts"
1253
- ]) {
1254
- let copyPath = path.replace(/(\.[^./]+)?$/, "-copy$1");
1255
- assert.deepEqual(await bytesOf(copyPath), await bytesOf(path), `${copyPath} has the same bytes as ${path}`);
1256
- }
1257
- });
1258
- (0, import_qunit.test)("a binary file exists, and is not overwritten", async function(assert) {
1259
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1260
- let run = (code) => command.execute({
1261
- realm: testRealmURL,
1262
- roomId: "!room:example.com",
1263
- code
1264
- });
1265
- let result = await run(`return await realm.fs.exists('images/existing.png');`);
1266
- assert.true(JSON.parse(result.scriptResult), "exists returns true");
1267
- await assert.rejects(run(`await realm.fs.copy('notes/first.md', 'images/existing.png');`), /File already exists: .*existing\.png/);
1268
- await assert.rejects(run(`await realm.fs.writeText('images/existing.png', 'text');`), /File already exists; use realm\.fs\.replace/);
1269
- });
1270
- (0, import_qunit.module)("realm.fs.download", function(hooks) {
1271
- const sourceURL = "https://media.example/images/pet.png";
1272
- let pngBytes = Uint8Array.from(atob(PNG_BASE64), (char) => char.charCodeAt(0));
1273
- let sourceRequests;
1274
- hooks.beforeEach(function() {
1275
- sourceRequests = [];
1276
- getService("network").virtualNetwork.mount(async (req) => {
1277
- if (!req.url.startsWith("https://media.example/")) return null;
1278
- sourceRequests.push(req.url);
1279
- if (req.url === sourceURL) return new Response(pngBytes, {
1280
- status: 200,
1281
- headers: { "Content-Type": "image/png" }
1282
- });
1283
- if (req.url.endsWith("/nine.bin")) return new Response(new Uint8Array(9e6), {
1284
- status: 200,
1285
- headers: { "Content-Type": "application/octet-stream" }
1286
- });
1287
- if (req.url.endsWith("/large.bin")) return new Response(new Uint8Array(10000001), {
1288
- status: 200,
1289
- headers: { "Content-Type": "application/octet-stream" }
1290
- });
1291
- return new Response("Not found", { status: 404 });
1292
- }, { prepend: true });
1293
- });
1294
- (0, import_qunit.test)("saves the file at a URL into the realm", async function(assert) {
1295
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1296
- let code = `return await realm.fs.download('${sourceURL}', 'images/pet.png');`;
1297
- assert.true(RunRealmCodeTool.neverAutoExecutesFor({ code }), "a run that names realm.fs.download waits for a click");
1298
- let result = await command.execute({
1299
- realm: testRealmURL,
1300
- roomId: "!room:example.com",
1301
- code
1302
- });
1303
- assert.deepEqual(JSON.parse(result.scriptResult), {
1304
- path: "images/pet.png",
1305
- size: pngBytes.byteLength,
1306
- saved: true
1307
- });
1308
- assert.deepEqual(result.files.map((file) => [
1309
- file.fileUrl,
1310
- file.status,
1311
- file.detail
1312
- ]), [[
1313
- `${testRealmURL}images/pet.png`,
1314
- "saved",
1315
- "Binary file saved."
1316
- ]]);
1317
- let response = await getService("network").authedFetch(new URL("images/pet.png", testRealmURL));
1318
- assert.strictEqual(response.status, 200);
1319
- assert.deepEqual(Array.from(new Uint8Array(await response.arrayBuffer())), Array.from(pngBytes), "the realm holds the downloaded bytes");
1320
- });
1321
- (0, import_qunit.test)("realm.fs.delete removes a file the same run downloaded", async function(assert) {
1322
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1323
- realm: testRealmURL,
1324
- roomId: "!room:example.com",
1325
- code: `await realm.fs.download('${sourceURL}', 'images/pet.png');
1326
- return {
1327
- deleted: await realm.fs.delete('images/pet.png'),
1328
- exists: await realm.fs.exists('images/pet.png'),
1329
- };`
1330
- });
1331
- assert.deepEqual(JSON.parse(result.scriptResult), {
1332
- deleted: {
1333
- path: "images/pet.png",
1334
- deleted: true
1335
- },
1336
- exists: false
1337
- });
1338
- assert.deepEqual(result.files.map((file) => [file.fileUrl, file.status]), [[`${testRealmURL}images/pet.png`, "deleted"]]);
1339
- });
1340
- (0, import_qunit.test)("refuses an existing file, a path with no extension, a source that is not http, and a failed download", async function(assert) {
1341
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1342
- let run = (code) => command.execute({
1343
- realm: testRealmURL,
1344
- roomId: "!room:example.com",
1345
- code
1346
- });
1347
- await assert.rejects(run(`await realm.fs.download('${sourceURL}', 'task.json');`), /File already exists/);
1348
- await assert.rejects(run(`await realm.fs.download('${sourceURL}', 'images/pet');`), /needs a path with a file extension/);
1349
- await assert.rejects(run(`await realm.fs.download('file:///etc/hosts', 'hosts.txt');`), /downloads only http and https URLs/);
1350
- assert.deepEqual(sourceRequests, [], "nothing was fetched so far");
1351
- await assert.rejects(run(`await realm.fs.download('https://media.example/missing.png', 'missing.png');`), /Unable to download https:\/\/media\.example\/missing\.png: 404.*No file was saved/);
1352
- });
1353
- (0, import_qunit.test)("refuses a file over the size limit", async function(assert) {
1354
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1355
- await assert.rejects(command.execute({
1356
- realm: testRealmURL,
1357
- roomId: "!room:example.com",
1358
- code: `await realm.fs.download('https://media.example/large.bin', 'large.bin');`
1359
- }), /at most 10000000 bytes per file.*No file was saved/);
1360
- });
1361
- (0, import_qunit.test)("a download whose save fails still counts toward the per-run limit", async function(assert) {
1362
- getService("network").virtualNetwork.mount(async (req) => {
1363
- if (req.method === "POST" && req.url.startsWith(`${testRealmURL}failing/`)) return new Response("Server error", { status: 500 });
1364
- return null;
1365
- }, { prepend: true });
1366
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1367
- realm: testRealmURL,
1368
- roomId: "!room:example.com",
1369
- code: `let errors = [];
1370
- for (let name of ['a', 'b', 'c']) {
1371
- try {
1372
- await realm.fs.download('https://media.example/nine.bin', 'failing/' + name + '.bin');
1373
- } catch (error) {
1374
- errors.push(error.message);
1375
- }
1376
- }
1377
- return errors;`
1378
- });
1379
- let errors = JSON.parse(result.scriptResult);
1380
- assert.strictEqual(errors.length, 3, "no save succeeded");
1381
- assert.notOk(/per run/.test(errors[0]), errors[0]);
1382
- assert.notOk(/per run/.test(errors[1]), errors[1]);
1383
- assert.ok(/at most 25000000 bytes per run/.test(errors[2]), "the third download is over the bytes the failed saves left");
1384
- });
1385
- (0, import_qunit.test)("a download the script did not await fails the run and is not fetched", async function(assert) {
1386
- getService("network").virtualNetwork.mount(async (req) => {
1387
- if (req.method === "GET" && req.url === `${testRealmURL}late.png`) await new Promise((resolve) => setTimeout(resolve, 1e3));
1388
- return null;
1389
- }, { prepend: true });
1390
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1391
- await assert.rejects(command.execute({
1392
- realm: testRealmURL,
1393
- roomId: "!room:example.com",
1394
- code: `realm.fs.download('${sourceURL}', 'late.png');
1395
- return 'done';`
1396
- }), /await every realm call/);
1397
- assert.deepEqual(sourceRequests, [], "nothing is fetched");
1398
- let response = await getService("network").authedFetch(new URL("late.png", testRealmURL));
1399
- assert.strictEqual(response.status, 404, "nothing is saved");
1400
- });
1401
- (0, import_qunit.test)("a script that reaches realm.fs.download another way is refused", async function(assert) {
1402
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1403
- let code = `await realm.fs['down' + 'load']('${sourceURL}', 'pet.png');`;
1404
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code }), "this run would not wait for a click");
1405
- await assert.rejects(command.execute({
1406
- realm: testRealmURL,
1407
- roomId: "!room:example.com",
1408
- code
1409
- }), /realm\.fs\.download must be called by that name/);
1410
- assert.deepEqual(sourceRequests, [], "nothing is fetched");
1411
- });
1412
- });
1413
- (0, import_qunit.test)("resolves paths against the realm root", async function(assert) {
1414
- let toolService = getService("tool-service");
1415
- let cardService = getService("card-service");
1416
- let command = new RunRealmCodeTool(toolService.toolContext);
1417
- let fileUrl = `${testRealmURL}task.json`;
1418
- let result = await command.execute({
1419
- realm: testRealmURL,
1420
- roomId: "!room:example.com",
1421
- code: `return await realm.fs.replace('task.json', '"count": 1', '"count": 2');`
1422
- });
1423
- assert.strictEqual(result.files[0]?.status, "saved");
1424
- assert.deepEqual(JSON.parse(result.scriptResult), {
1425
- path: "task.json",
1426
- matches: 1,
1427
- saved: true
1428
- });
1429
- let source = await cardService.getSource(new URL(fileUrl));
1430
- assert.true(source.content.includes("\"count\": 2"));
1431
- });
1432
- (0, import_qunit.test)("resolves paths against the realm root named without its trailing slash", async function(assert) {
1433
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1434
- realm: testRealmURL.replace(/\/$/, ""),
1435
- roomId: "!room:example.com",
1436
- code: `return await realm.fs.readText('task.json');`
1437
- });
1438
- assert.true(JSON.parse(result.scriptResult).includes("\"count\""));
1439
- });
1440
- (0, import_qunit.test)("refuses a folder in the realm as the realm, and names the root and the path to use", async function(assert) {
1441
- let toolService = getService("tool-service");
1442
- let cardService = getService("card-service");
1443
- let command = new RunRealmCodeTool(toolService.toolContext);
1444
- let folder = `${testRealmURL}card-mutation/relink/`;
1445
- for (let realm of [folder, folder.replace(/\/$/, "")]) await assert.rejects(command.execute({
1446
- realm,
1447
- roomId: "!room:example.com",
1448
- code: `return await realm.fs.replace('task.json', '"count": 1', '"count": 2');`
1449
- }), (error) => error.message === `${realm} is card-mutation/relink inside the workspace ${testRealmURL}, not its root. Pass ${testRealmURL} as realm, and name each file by its path from there: card-mutation/relink for that file, card-mutation/relink.json for that card, or card-mutation/relink/ and the file's name for a file in that folder`);
1450
- let source = await cardService.getSource(new URL(`${testRealmURL}task.json`));
1451
- assert.true(source.content.includes("\"count\": 1"), "the script does not run against the root");
1452
- });
1453
- (0, import_qunit.test)("refuses a file or card in the realm as the realm, and names it by its path from the root", async function(assert) {
1454
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1455
- for (let local of [
1456
- "Event/intro-to-pottery.json",
1457
- "Event/intro-to-pottery",
1458
- "docs/README"
1459
- ]) {
1460
- let realm = `${testRealmURL}${local}`;
1461
- await assert.rejects(command.execute({
1462
- realm,
1463
- roomId: "!room:example.com",
1464
- code: `return 'ran';`
1465
- }), (error) => error.message === `${realm} is ${local} inside the workspace ${testRealmURL}, not its root. Pass ${testRealmURL} as realm, and name each file by its path from there: ${local} for that file, ${local}.json for that card, or ${local}/ and the file's name for a file in that folder`);
1466
- }
1467
- });
1468
- (0, import_qunit.test)("refuses a realm with a malformed percent-encoding as one it cannot reach", async function(assert) {
1469
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1470
- let realm = `${testRealmURL}folder%E0/`;
1471
- await assert.rejects(command.execute({
1472
- realm,
1473
- roomId: "!room:example.com",
1474
- code: `return 'ran';`
1475
- }), (error) => error.message === `The current user cannot read or write ${realm}`);
1476
- });
1477
- (0, import_qunit.test)("reads files and cards named by the prefix of the realm it runs in", async function(assert) {
1478
- let { virtualNetwork } = getService("network");
1479
- let prefix = "@test/path-prefix/";
1480
- virtualNetwork.addRealmMapping(prefix, testRealmURL);
1481
- try {
1482
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1483
- let result = await command.execute({
1484
- realm: testRealmURL,
1485
- roomId: "!room:example.com",
1486
- code: `let byPrefix = await realm.cards.get('${prefix}people/hassan');
1487
- let byURL = await realm.cards.get(${JSON.stringify(`${testRealmURL}people/hassan`)});
1488
- let listByPrefix = await realm.fs.list('${prefix}people/');
1489
- let listByURL = await realm.fs.list(${JSON.stringify(`${testRealmURL}people/`)});
1490
- let rootByPrefix = await realm.fs.list('${prefix}');
1491
- let rootByURL = await realm.fs.list('');
1492
- return { byPrefix, byURL, listByPrefix, listByURL, rootByPrefix, rootByURL };`
1493
- });
1494
- let { byPrefix, byURL, listByPrefix, listByURL, rootByPrefix, rootByURL } = JSON.parse(result.scriptResult);
1495
- assert.deepEqual(byPrefix, byURL, "a card reads the same by prefix");
1496
- assert.deepEqual(listByPrefix, listByURL, "a folder lists the same by prefix");
1497
- assert.deepEqual(rootByPrefix, rootByURL, "the realm root lists the same by prefix");
1498
- await assert.rejects(command.execute({
1499
- realm: testRealmURL,
1500
- roomId: "!room:example.com",
1501
- code: `await realm.cards.get('@test/unregistered/people/hassan');`
1502
- }), /Path is outside this realm/);
1503
- } finally {
1504
- virtualNetwork.removeRealmMapping(prefix);
1505
- }
1506
- });
1507
- (0, import_qunit.test)("refuses a folder of a realm named by a prefix, and names the root by that prefix", async function(assert) {
1508
- let { virtualNetwork } = getService("network");
1509
- let prefix = "@test/folder-input/";
1510
- virtualNetwork.addRealmMapping(prefix, testRealmURL);
1511
- try {
1512
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1513
- let folder = `${prefix}card-mutation/relink/`;
1514
- await assert.rejects(command.execute({
1515
- realm: folder,
1516
- roomId: "!room:example.com",
1517
- code: `return 'ran';`
1518
- }), (error) => error.message === `${folder} is card-mutation/relink inside the workspace ${prefix}, not its root. Pass ${prefix} as realm, and name each file by its path from there: card-mutation/relink for that file, card-mutation/relink.json for that card, or card-mutation/relink/ and the file's name for a file in that folder`);
1519
- } finally {
1520
- virtualNetwork.removeRealmMapping(prefix);
1521
- }
1522
- });
1523
- (0, import_qunit.test)("runs in the realm root named with a query string", async function(assert) {
1524
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1525
- realm: `${testRealmURL}?x=1`,
1526
- roomId: "!room:example.com",
1527
- code: `return await realm.fs.readText('task.json');`
1528
- });
1529
- assert.true(JSON.parse(result.scriptResult).includes("\"count\""));
1530
- });
1531
- (0, import_qunit.test)("runs in a workspace nested under the realm, learned after it", async function(assert) {
1532
- let nestedRealmURL = `${testRealmURL}nested/`;
1533
- knowReadableWorkspace(nestedRealmURL);
1534
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1535
- realm: nestedRealmURL,
1536
- roomId: "!room:example.com",
1537
- code: `return 'ran';`
1538
- });
1539
- assert.strictEqual(JSON.parse(result.scriptResult), "ran");
1540
- });
1541
- (0, import_qunit.test)("asks a workspace nested under the realm for its own permissions", async function(assert) {
1542
- let nestedRealmURL = `${testRealmURL}nested/`;
1543
- knowReadableWorkspace(nestedRealmURL, []);
1544
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1545
- await assert.rejects(command.execute({
1546
- realm: nestedRealmURL,
1547
- roomId: "!room:example.com",
1548
- code: `return 'ran';`
1549
- }), (error) => error.message === `The current user cannot read or write ${nestedRealmURL}`, "the readable outer realm does not answer for the nested one");
1550
- });
1551
- (0, import_qunit.test)("refuses paths outside the realm, and names the files it already saved", async function(assert) {
1552
- let toolService = getService("tool-service");
1553
- let cardService = getService("card-service");
1554
- let command = new RunRealmCodeTool(toolService.toolContext);
1555
- let fileUrl = `${testRealmURL}task.json`;
1556
- await assert.rejects(command.execute({
1557
- realm: testRealmURL,
1558
- roomId: "!room:example.com",
1559
- code: `await realm.fs.replace('task.json', '"count": 1', '"count": 2');
1560
- await realm.fs.writeText('../elsewhere.json', '{}');`
1561
- }), /Path must be relative to the realm root.*Files already saved by this run: .*task\.json/);
1562
- let source = await cardService.getSource(new URL(fileUrl));
1563
- assert.true(source.content.includes("\"count\": 2"));
1564
- });
1565
- (0, import_qunit.test)("reads a file inside the script and edits it from what it read", async function(assert) {
1566
- let toolService = getService("tool-service");
1567
- let cardService = getService("card-service");
1568
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
1569
- realm: testRealmURL,
1570
- roomId: "!room:example.com",
1571
- code: `const task = JSON.parse(await realm.fs.readText('task.json'));
1572
- await realm.fs.replace('task.json', '"count": ' + task.count, '"count": ' + (task.count + 1));
1573
- return { exists: await realm.fs.exists('task.json'), missing: await realm.fs.exists('nope.json') };`
1574
- });
1575
- assert.strictEqual(result.files[0]?.status, "saved");
1576
- assert.deepEqual(JSON.parse(result.scriptResult), {
1577
- exists: true,
1578
- missing: false
1579
- });
1580
- let source = await cardService.getSource(new URL(`${testRealmURL}task.json`));
1581
- assert.true(source.content.includes("\"count\": 2"));
1582
- });
1583
- (0, import_qunit.test)("each write is saved before the script goes on", async function(assert) {
1584
- let toolService = getService("tool-service");
1585
- let cardService = getService("card-service");
1586
- let command = new RunRealmCodeTool(toolService.toolContext);
1587
- await assert.rejects(command.execute({
1588
- realm: testRealmURL,
1589
- roomId: "!room:example.com",
1590
- code: `await realm.fs.writeText('first.json', '{}');
1591
- throw new Error('stop here');`
1592
- }), /stop here.*Files already saved by this run: .*first\.json/);
1593
- let source = await cardService.getSource(new URL(`${testRealmURL}first.json`));
1594
- assert.strictEqual(source.status, 200);
1595
- });
1596
- (0, import_qunit.test)("a thrown message that ends a sentence gets no second period", async function(assert) {
1597
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1598
- await assert.rejects(command.execute({
1599
- realm: testRealmURL,
1600
- roomId: "!room:example.com",
1601
- code: `throw new Error('Could not find the styles.');`
1602
- }), /Could not find the styles\. No file was saved\./);
1603
- });
1604
- (0, import_qunit.test)("a caught failed write does not fail the run", async function(assert) {
1605
- let toolService = getService("tool-service");
1606
- let cardService = getService("card-service");
1607
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
1608
- realm: testRealmURL,
1609
- roomId: "!room:example.com",
1610
- code: `await realm.fs.replace('task.json', '"count": 1', '"count": 2');
1611
- try { await realm.fs.replace('task.json', 'not there', 'x'); } catch (e) {}
1612
- return 'done';`
1613
- });
1614
- assert.strictEqual(result.files.length, 1);
1615
- assert.strictEqual(result.files[0]?.status, "saved");
1616
- let source = await cardService.getSource(new URL(`${testRealmURL}task.json`));
1617
- assert.true(source.content.includes("\"count\": 2"));
1618
- });
1619
- (0, import_qunit.test)("a caught failed read does not fail the run", async function(assert) {
1620
- let toolService = getService("tool-service");
1621
- let cardService = getService("card-service");
1622
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
1623
- realm: testRealmURL,
1624
- roomId: "!room:example.com",
1625
- code: `let found = true;
1626
- try { await realm.fs.readText('new-task.json'); } catch (e) { found = false; }
1627
- if (!found) await realm.fs.writeText('new-task.json', '{}');
1628
- return found;`
1629
- });
1630
- assert.strictEqual(result.files[0]?.status, "saved");
1631
- let source = await cardService.getSource(new URL(`${testRealmURL}new-task.json`));
1632
- assert.strictEqual(source.status, 200);
1633
- });
1634
- (0, import_qunit.test)("a realm call the script does not await fails the run, and the report says whether it saved", async function(assert) {
1635
- let toolService = getService("tool-service");
1636
- let cardService = getService("card-service");
1637
- let command = new RunRealmCodeTool(toolService.toolContext);
1638
- let error;
1639
- try {
1640
- await command.execute({
1641
- realm: testRealmURL,
1642
- roomId: "!room:example.com",
1643
- code: `realm.fs.writeText('late.json', '{}');`
1644
- });
1645
- } catch (e) {
1646
- error = e;
1647
- }
1648
- assert.ok(error, "the run rejected");
1649
- assert.true(/await every realm call/.test(error?.message ?? ""), `the error says to await every realm call: ${error?.message}`);
1650
- let reportedSaved = /Files already saved by this run: .*late\.json/.test(error?.message ?? "");
1651
- let reportedNoneSaved = /No file was saved/.test(error?.message ?? "");
1652
- assert.notStrictEqual(reportedSaved, reportedNoneSaved, `the report says either that late.json was saved or that nothing was: ${error?.message}`);
1653
- await settled();
1654
- let source = await cardService.getSource(new URL(`${testRealmURL}late.json`));
1655
- assert.strictEqual(source.status, reportedSaved ? 200 : 404, reportedSaved ? "the file the report names as saved is in the realm" : "the report said nothing was saved, and nothing landed after it");
1656
- });
1657
- (0, import_qunit.test)("a script that never returns is stopped by the sandbox, not by the caller", async function(assert) {
1658
- let error;
1659
- try {
1660
- await runRealmCode({
1661
- code: "while (true) {}",
1662
- realmURL: testRealmURL,
1663
- timeoutMs: 500
1664
- }, async () => null);
1665
- } catch (e) {
1666
- error = e;
1667
- }
1668
- assert.ok(error, "the run rejected");
1669
- assert.strictEqual(error?.message, "interrupted");
1670
- });
1671
- (0, import_qunit.test)("lists a directory without counting toward the file limit", async function(assert) {
1672
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1673
- let result = await command.execute({
1674
- realm: testRealmURL,
1675
- roomId: "!room:example.com",
1676
- code: `return {
1677
- root: await realm.fs.list(),
1678
- notes: await realm.fs.list('notes'),
1679
- notesWithSlash: await realm.fs.list('notes/'),
1680
- notesByURL: await realm.fs.list(${JSON.stringify(`${testRealmURL}notes/`)}),
1681
- };`
1682
- });
1683
- assert.deepEqual(result.files, [], "a listing saves nothing");
1684
- let listed = JSON.parse(result.scriptResult);
1685
- assert.deepEqual(listed.root.find((entry) => entry.name === "task.json"), {
1686
- name: "task.json",
1687
- path: "task.json",
1688
- kind: "file"
1689
- });
1690
- assert.deepEqual(listed.root.find((entry) => entry.name === "notes"), {
1691
- name: "notes",
1692
- path: "notes/",
1693
- kind: "directory"
1694
- });
1695
- let notes = [{
1696
- name: "first.md",
1697
- path: "notes/first.md",
1698
- kind: "file"
1699
- }];
1700
- assert.deepEqual(listed.notes, notes);
1701
- assert.deepEqual(listed.notesWithSlash, notes);
1702
- assert.deepEqual(listed.notesByURL, notes);
1703
- await assert.rejects(command.execute({
1704
- realm: testRealmURL,
1705
- roomId: "!room:example.com",
1706
- code: `await realm.fs.list('../');`
1707
- }), /Path must be relative to the realm root/);
1708
- await assert.rejects(command.execute({
1709
- realm: testRealmURL,
1710
- roomId: "!room:example.com",
1711
- code: `await realm.fs.list('missing');`
1712
- }), /Directory not found/);
1713
- });
1714
- (0, import_qunit.test)("realm.entries.search runs several searches in one script and returns only what the script keeps", async function(assert) {
1715
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1716
- realm: testRealmURL,
1717
- roomId: "!room:example.com",
1718
- code: `const found = {};
1719
- for (const title of ['Pet', 'Unicorn']) {
1720
- const { entries, total, truncated, incomplete } = await realm.entries.search(
1721
- {
1722
- filter: {
1723
- on: { module: '@cardstack/base/spec', name: 'Spec' },
1724
- eq: { cardTitle: title },
1725
- },
1726
- },
1727
- { realms: [realm.current.url] },
1728
- );
1729
- found[title] = {
1730
- total,
1731
- truncated,
1732
- incomplete,
1733
- entries: entries.map((entry) => ({
1734
- url: entry.url,
1735
- kind: entry.kind,
1736
- specType: entry.specType,
1737
- refName: entry.ref?.name,
1738
- readMe: entry.readMe,
1739
- })),
1740
- };
1741
- }
1742
- return found;`
1743
- });
1744
- assert.deepEqual(result.files, [], "a search saves nothing");
1745
- assert.deepEqual(JSON.parse(result.scriptResult), {
1746
- Pet: {
1747
- total: 1,
1748
- truncated: false,
1749
- incomplete: false,
1750
- entries: [{
1751
- url: `${testRealmURL}Spec/pet`,
1752
- kind: "card",
1753
- specType: "card",
1754
- refName: "Pet",
1755
- readMe: "# Pet\n\nUse Pet for any animal with a name."
1756
- }]
1757
- },
1758
- Unicorn: {
1759
- total: 0,
1760
- truncated: false,
1761
- incomplete: false,
1762
- entries: []
1763
- }
1764
- });
1765
- });
1766
- (0, import_qunit.test)("realm.entries.search caps the entries at the limit and reports the rest", async function(assert) {
1767
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1768
- realm: testRealmURL,
1769
- roomId: "!room:example.com",
1770
- code: `const { entries, total, truncated } = await realm.entries.search(
1771
- {},
1772
- { realms: [realm.current.url], scope: 'cards', limit: 1 },
1773
- );
1774
- return { count: entries.length, kind: entries[0].kind, more: total > 1, truncated };`
1775
- });
1776
- assert.deepEqual(JSON.parse(result.scriptResult), {
1777
- count: 1,
1778
- kind: "card",
1779
- more: true,
1780
- truncated: true
1781
- });
1782
- });
1783
- (0, import_qunit.test)("realm.entries.search finds the entries of a realm named by a registered prefix", async function(assert) {
1784
- let { virtualNetwork } = getService("network");
1785
- virtualNetwork.addRealmMapping("@test/mapped/", otherRealmURL);
1786
- try {
1787
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1788
- realm: testRealmURL,
1789
- roomId: "!room:example.com",
1790
- code: `const { entries, total, incomplete } = await realm.entries.search(
1791
- {
1792
- filter: {
1793
- on: { module: ${JSON.stringify(`${testRealmURL}recipe`)}, name: 'Recipe' },
1794
- eq: { name: 'Elsewhere' },
1795
- },
1796
- },
1797
- { realms: ['@test/mapped'], scope: 'cards' },
1798
- );
1799
- return { total, incomplete, urls: entries.map((entry) => entry.url) };`
1800
- });
1801
- assert.deepEqual(JSON.parse(result.scriptResult), {
1802
- total: 1,
1803
- incomplete: false,
1804
- urls: [`${otherRealmURL}Recipe/elsewhere`]
1805
- });
1806
- } finally {
1807
- virtualNetwork.removeRealmMapping("@test/mapped/");
1808
- }
1809
- });
1810
- (0, import_qunit.test)("realm.entries.search sends a realm as the identifier given, once per realm", async function(assert) {
1811
- let { virtualNetwork } = getService("network");
1812
- let sentRealms = [];
1813
- let spy = async (request) => {
1814
- if (new URL(request.url).pathname.endsWith("/_federated-search")) sentRealms.push(JSON.parse(await request.clone().text()).realms);
1815
- return null;
1816
- };
1817
- virtualNetwork.mount(spy, { prepend: true });
1818
- try {
1819
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1820
- await command.execute({
1821
- realm: testRealmURL,
1822
- roomId: "!room:example.com",
1823
- code: `await realm.entries.search({}, { realms: ['@cardstack/base/', ${JSON.stringify(virtualNetwork.toURL("@cardstack/base/").href)}] });`
1824
- });
1825
- assert.deepEqual(sentRealms, [["@cardstack/base/"]], "the prefix goes out as given, and its URL, naming the same realm, is dropped");
1826
- await command.execute({
1827
- realm: testRealmURL,
1828
- roomId: "!room:example.com",
1829
- code: `await realm.entries.search({}, { realms: ['@cardstack/base/'] });`
1830
- });
1831
- assert.deepEqual(sentRealms[1], ["@cardstack/base/"], "the base prefix goes out as given");
1832
- } finally {
1833
- virtualNetwork.unmount(spy);
1834
- }
1835
- });
1836
- (0, import_qunit.test)("realm.entries.search refuses a scoped identifier no realm is registered under", async function(assert) {
1837
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1838
- await assert.rejects(command.execute({
1839
- realm: testRealmURL,
1840
- roomId: "!room:example.com",
1841
- code: `await realm.entries.search({}, { realms: ['@nope/realm/'] });`
1842
- }), (error) => error.message.includes("Unknown realm identifier \"@nope/realm/\"") && error.message.includes("@cardstack/catalog/"));
1843
- await assert.rejects(command.execute({
1844
- realm: testRealmURL,
1845
- roomId: "!room:example.com",
1846
- code: `await realm.entries.search({}, { realms: ['@cardstack/boxel-ui/'] });`
1847
- }), /Unknown realm identifier "@cardstack\/boxel-ui\/"/);
1848
- });
1849
- (0, import_qunit.test)("realm.entries.search refuses a page and an unknown scope", async function(assert) {
1850
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1851
- await assert.rejects(command.execute({
1852
- realm: testRealmURL,
1853
- roomId: "!room:example.com",
1854
- code: `await realm.entries.search({ page: { number: 1 } });`
1855
- }), /does not page; pass \{ limit \}/);
1856
- await assert.rejects(command.execute({
1857
- realm: testRealmURL,
1858
- roomId: "!room:example.com",
1859
- code: `await realm.entries.search({}, { scope: 'modules' });`
1860
- }), /Invalid scope "modules"/);
1861
- });
1862
- function stubWorkspaceCreation() {
1863
- let calls = [];
1864
- let realmServer = getService("realm-server");
1865
- realmServer.createRealm = async (args) => {
1866
- calls.push(args);
1867
- return new URL(`http://test-realm/testuser/${args.endpoint}/`);
1868
- };
1869
- getService("realm").ensureRealmMeta = async () => {};
1870
- return calls;
1871
- }
1872
- (0, import_qunit.test)("realm.workspaces.create creates a workspace, returns its URL, and opens it after the run", async function(assert) {
1873
- let createRealmCalls = stubWorkspaceCreation();
1874
- let operatorModeStateService = getService("operator-mode-state-service");
1875
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1876
- realm: testRealmURL,
1877
- roomId: "!room:example.com",
1878
- code: `let created = await realm.workspaces.create({ name: 'Sales Pipeline' });
1879
- return { created, realmAfterCreate: realm.current.url };`
1880
- });
1881
- assert.deepEqual(createRealmCalls.map(({ endpoint, name }) => ({
1882
- endpoint,
1883
- name
1884
- })), [{
1885
- endpoint: "sales-pipeline",
1886
- name: "Sales Pipeline"
1887
- }], "the endpoint is derived from the name, as the create-workspace tool does");
1888
- assert.deepEqual(JSON.parse(result.scriptResult), {
1889
- created: {
1890
- url: "http://test-realm/testuser/sales-pipeline/",
1891
- name: "Sales Pipeline"
1892
- },
1893
- realmAfterCreate: testRealmURL
1894
- });
1895
- assert.strictEqual(operatorModeStateService.state?.stacks[0]?.[0]?.id, "http://test-realm/testuser/sales-pipeline/index", "the new workspace is opened once the run ends");
1896
- assert.deepEqual(result.createdWorkspaces, ["http://test-realm/testuser/sales-pipeline/"], "the result names the created workspace");
1897
- });
1898
- (0, import_qunit.test)("a failed run names the workspaces it created and opens none", async function(assert) {
1899
- stubWorkspaceCreation();
1900
- let operatorModeStateService = getService("operator-mode-state-service");
1901
- let stackBefore = operatorModeStateService.state?.stacks[0]?.[0]?.id;
1902
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1903
- await assert.rejects(command.execute({
1904
- realm: testRealmURL,
1905
- roomId: "!room:example.com",
1906
- code: `await realm.workspaces.create({ name: 'First Try' });
1907
- throw new Error('boom');`
1908
- }), /boom.*Workspaces already created by this run: http:\/\/test-realm\/testuser\/first-try\//);
1909
- assert.strictEqual(operatorModeStateService.state?.stacks[0]?.[0]?.id, stackBefore, "no workspace is opened after a failed run");
1910
- });
1911
- (0, import_qunit.test)("a run that saves files and creates a workspace stays in its realm", async function(assert) {
1912
- stubWorkspaceCreation();
1913
- let operatorModeStateService = getService("operator-mode-state-service");
1914
- let stackBefore = operatorModeStateService.state?.stacks[0]?.[0]?.id;
1915
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1916
- realm: testRealmURL,
1917
- roomId: "!room:example.com",
1918
- code: `await realm.fs.writeText('notes/new-workspace.txt', 'hello');
1919
- await realm.workspaces.create({ name: 'Side Project' });`
1920
- });
1921
- assert.deepEqual(result.createdWorkspaces, ["http://test-realm/testuser/side-project/"]);
1922
- assert.strictEqual(operatorModeStateService.state?.stacks[0]?.[0]?.id, stackBefore, "the new workspace is not opened, so the next run defaults to this realm");
1923
- });
1924
- (0, import_qunit.test)("realm.workspaces.create refuses options that are not strings", async function(assert) {
1925
- let createRealmCalls = stubWorkspaceCreation();
1926
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1927
- await assert.rejects(command.execute({
1928
- realm: testRealmURL,
1929
- roomId: "!room:example.com",
1930
- code: `await realm.workspaces.create({ name: 42 });`
1931
- }), /expects name to be a string/);
1932
- assert.strictEqual(createRealmCalls.length, 0, "no realm is created");
1933
- });
1934
- function stubWorkspaceDeletion(ownedRealmURL) {
1935
- let calls = [];
1936
- getService("realm-server").deleteRealm = async (realmURL) => {
1937
- calls.push(realmURL);
1938
- };
1939
- let realmService = getService("realm");
1940
- let isRealmOwner = realmService.isRealmOwner.bind(realmService);
1941
- realmService.isRealmOwner = (url) => url === ownedRealmURL || isRealmOwner(url);
1942
- return calls;
1943
- }
1944
- (0, import_qunit.test)("a script that deletes a workspace always waits for the user", function(assert) {
1945
- assert.true(RunRealmCodeTool.neverAutoExecutesFor({ code: `await realm.workspaces.delete('http://test-realm/testuser/old/');` }), "a run that names realm.workspaces.delete waits for a click");
1946
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code: `await realm.fs.writeText('a.json', '{}');` }), "other runs keep the room mode");
1947
- assert.false(RunRealmCodeTool.neverAutoExecutesFor(void 0), "a call whose input has not arrived yet is not judged");
1948
- });
1949
- (0, import_qunit.test)("realm.workspaces.delete deletes a workspace the user owns", async function(assert) {
1950
- let oldWorkspace = "http://test-realm/testuser/old/";
1951
- let deleteRealmCalls = stubWorkspaceDeletion(oldWorkspace);
1952
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1953
- realm: testRealmURL,
1954
- roomId: "!room:example.com",
1955
- code: `return await realm.workspaces.delete('${oldWorkspace}');`
1956
- });
1957
- assert.deepEqual(deleteRealmCalls, [oldWorkspace]);
1958
- assert.deepEqual(JSON.parse(result.scriptResult), {
1959
- url: oldWorkspace,
1960
- deleted: true
1961
- });
1962
- });
1963
- (0, import_qunit.test)("the result names the deleted workspace when the script does not return it", async function(assert) {
1964
- let oldWorkspace = "http://test-realm/testuser/old/";
1965
- stubWorkspaceDeletion(oldWorkspace);
1966
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1967
- realm: testRealmURL,
1968
- roomId: "!room:example.com",
1969
- code: `await realm.workspaces.delete('${oldWorkspace}');`
1970
- });
1971
- assert.deepEqual(result.deletedWorkspaces, [oldWorkspace]);
1972
- });
1973
- (0, import_qunit.test)("a failed run names the workspaces it deleted", async function(assert) {
1974
- let oldWorkspace = "http://test-realm/testuser/old/";
1975
- stubWorkspaceDeletion(oldWorkspace);
1976
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
1977
- await assert.rejects(command.execute({
1978
- realm: testRealmURL,
1979
- roomId: "!room:example.com",
1980
- code: `await realm.workspaces.delete('${oldWorkspace}');
1981
- throw new Error('boom');`
1982
- }), /boom.*Workspaces already deleted by this run: http:\/\/test-realm\/testuser\/old\//);
1983
- });
1984
- (0, import_qunit.test)("a workspace recreated at a URL the run deleted is opened", async function(assert) {
1985
- let oldWorkspace = "http://test-realm/testuser/old/";
1986
- stubWorkspaceDeletion(oldWorkspace);
1987
- stubWorkspaceCreation();
1988
- let operatorModeStateService = getService("operator-mode-state-service");
1989
- await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
1990
- realm: testRealmURL,
1991
- roomId: "!room:example.com",
1992
- code: `await realm.workspaces.delete('${oldWorkspace}');
1993
- await realm.workspaces.create({ name: 'Old' });`
1994
- });
1995
- assert.strictEqual(operatorModeStateService.state?.stacks[0]?.[0]?.id, `${oldWorkspace}index`);
1996
- });
1997
- (0, import_qunit.test)("realm.workspaces.delete refuses a workspace the user does not own", async function(assert) {
1998
- let deleteRealmCalls = stubWorkspaceDeletion("http://test-realm/testuser/old/");
1999
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2000
- await assert.rejects(command.execute({
2001
- realm: testRealmURL,
2002
- roomId: "!room:example.com",
2003
- code: `await realm.workspaces.delete('http://test-realm/someone-else/theirs/');`
2004
- }), /the current user is not its owner/);
2005
- assert.deepEqual(deleteRealmCalls, [], "no realm is deleted");
2006
- });
2007
- (0, import_qunit.test)("a script that reaches realm.workspaces.delete another way is refused", async function(assert) {
2008
- let oldWorkspace = "http://test-realm/testuser/old/";
2009
- let deleteRealmCalls = stubWorkspaceDeletion(oldWorkspace);
2010
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2011
- let code = `let workspaces = realm.workspaces;
2012
- await workspaces['del' + 'ete']('${oldWorkspace}');`;
2013
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code }), "this run would not wait for a click");
2014
- await assert.rejects(command.execute({
2015
- realm: testRealmURL,
2016
- roomId: "!room:example.com",
2017
- code
2018
- }), /must be called by that name/);
2019
- assert.deepEqual(deleteRealmCalls, [], "no realm is deleted");
2020
- });
2021
- function stubIndexing() {
2022
- let calls = [];
2023
- let realmService = getService("realm");
2024
- realmService.invalidateUrls = async (realm, urls) => {
2025
- calls.push({
2026
- action: "invalidate",
2027
- realm,
2028
- urls
2029
- });
2030
- };
2031
- realmService.reindex = async (realm) => {
2032
- calls.push({
2033
- action: "reindex",
2034
- realm
2035
- });
2036
- };
2037
- realmService.fullReindex = async (realm) => {
2038
- calls.push({
2039
- action: "fullReindex",
2040
- realm
2041
- });
2042
- };
2043
- realmService.cancelIndexingJob = async (realm) => {
2044
- calls.push({
2045
- action: "cancelJob",
2046
- realm
2047
- });
2048
- };
2049
- return calls;
2050
- }
2051
- (0, import_qunit.test)("realm.index.invalidate and realm.index.reindex refresh the index of the run realm without a click", async function(assert) {
2052
- let calls = stubIndexing();
2053
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2054
- let code = `return {
2055
- invalidated: await realm.index.invalidate(['Pet/mango.json', '${testRealmURL}pet.gts']),
2056
- one: await realm.index.invalidate('task.json'),
2057
- reindex: await realm.index.reindex(),
2058
- };`;
2059
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code }), "the run keeps the room mode");
2060
- let result = await command.execute({
2061
- realm: testRealmURL,
2062
- roomId: "!room:example.com",
2063
- code
2064
- });
2065
- assert.deepEqual(calls, [
2066
- {
2067
- action: "invalidate",
2068
- realm: testRealmURL,
2069
- urls: [`${testRealmURL}Pet/mango.json`, `${testRealmURL}pet.gts`]
2070
- },
2071
- {
2072
- action: "invalidate",
2073
- realm: testRealmURL,
2074
- urls: [`${testRealmURL}task.json`]
2075
- },
2076
- {
2077
- action: "reindex",
2078
- realm: testRealmURL
2079
- }
2080
- ]);
2081
- assert.deepEqual(JSON.parse(result.scriptResult), {
2082
- invalidated: { invalidated: ["Pet/mango.json", "pet.gts"] },
2083
- one: { invalidated: ["task.json"] },
2084
- reindex: { reindex: "started" }
2085
- });
2086
- assert.deepEqual(result.indexActions, [
2087
- "invalidate Pet/mango.json, pet.gts",
2088
- "invalidate task.json",
2089
- "reindex"
2090
- ]);
2091
- });
2092
- (0, import_qunit.test)("realm.index.invalidate refuses a path outside the realm and an empty list", async function(assert) {
2093
- let calls = stubIndexing();
2094
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2095
- realm: testRealmURL,
2096
- roomId: "!room:example.com",
2097
- code: `let refused = [];
2098
- try { await realm.index.invalidate(['http://other-realm/a.json']); } catch (e) { refused.push(e.message); }
2099
- try { await realm.index.invalidate([]); } catch (e) { refused.push(e.message); }
2100
- return refused;`
2101
- });
2102
- let [outside, empty] = JSON.parse(result.scriptResult);
2103
- assert.true(/Path is outside this realm/.test(outside), outside);
2104
- assert.true(/expects a path or an array/.test(empty), empty);
2105
- assert.deepEqual(calls, [], "nothing is invalidated");
2106
- });
2107
- (0, import_qunit.test)("a script that starts a full reindex or cancels an indexing job always waits for the user", async function(assert) {
2108
- let calls = stubIndexing();
2109
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2110
- for (let code of [`await realm.index.fullReindex();`, `await realm.index.cancelJob();`]) assert.true(RunRealmCodeTool.neverAutoExecutesFor({ code }), `waits for a click: ${code}`);
2111
- let result = await command.execute({
2112
- realm: testRealmURL,
2113
- roomId: "!room:example.com",
2114
- code: `return {
2115
- cancel: await realm.index.cancelJob(),
2116
- full: await realm.index.fullReindex(),
2117
- };`
2118
- });
2119
- assert.deepEqual(calls, [{
2120
- action: "cancelJob",
2121
- realm: testRealmURL
2122
- }, {
2123
- action: "fullReindex",
2124
- realm: testRealmURL
2125
- }]);
2126
- assert.deepEqual(JSON.parse(result.scriptResult), {
2127
- cancel: { cancelled: true },
2128
- full: { fullReindex: "started" }
2129
- });
2130
- });
2131
- (0, import_qunit.test)("a failed run names the index actions it already started", async function(assert) {
2132
- let calls = stubIndexing();
2133
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2134
- await assert.rejects(command.execute({
2135
- realm: testRealmURL,
2136
- roomId: "!room:example.com",
2137
- code: `await realm.index.invalidate('task.json');
2138
- await realm.index.fullReindex();
2139
- throw new Error('boom');`
2140
- }), /boom\. No file was saved\. Index actions already started by this run: invalidate task\.json; fullReindex/);
2141
- assert.deepEqual(calls, [{
2142
- action: "invalidate",
2143
- realm: testRealmURL,
2144
- urls: [`${testRealmURL}task.json`]
2145
- }, {
2146
- action: "fullReindex",
2147
- realm: testRealmURL
2148
- }]);
2149
- });
2150
- (0, import_qunit.test)("a script that reaches realm.index.fullReindex another way is refused", async function(assert) {
2151
- let calls = stubIndexing();
2152
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2153
- let code = `let index = realm.index;
2154
- await index['full' + 'Reindex']();`;
2155
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code }), "this run would not wait for a click");
2156
- await assert.rejects(command.execute({
2157
- realm: testRealmURL,
2158
- roomId: "!room:example.com",
2159
- code
2160
- }), /realm\.index\.fullReindex must be called by that name/);
2161
- assert.deepEqual(calls, [], "no reindex starts");
2162
- });
2163
- (0, import_qunit.module)("room actions", function(hooks) {
2164
- let roomId;
2165
- let skillId = `${testRealmURL}skills/test-skill/SKILL.md`;
2166
- let model = DEFAULT_FALLBACK_MODELS[0].modelId;
2167
- hooks.beforeEach(async function() {
2168
- await getService("matrix-service").ready;
2169
- roomId = mockMatrixUtils.createAndJoinRoom({
2170
- sender: "@testuser:localhost",
2171
- name: "room-actions"
2172
- });
2173
- });
2174
- (0, import_qunit.test)("room actions change the room after the script finishes", async function(assert) {
2175
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2176
- let result = await command.execute({
2177
- realm: testRealmURL,
2178
- roomId,
2179
- code: `return {
2180
- skills: await room.enableSkills([${JSON.stringify(skillId)}]),
2181
- model: await room.setModel(${JSON.stringify(model)}),
2182
- };`
2183
- });
2184
- assert.deepEqual(JSON.parse(result.scriptResult), {
2185
- skills: {
2186
- enable: [skillId],
2187
- appliedAfterRun: true
2188
- },
2189
- model: {
2190
- model,
2191
- appliedAfterRun: true
2192
- }
2193
- });
2194
- let skills = mockMatrixUtils.getRoomState(roomId, APP_BOXEL_ROOM_SKILLS_EVENT_TYPE);
2195
- assert.deepEqual(skills.enabledSkillCards.map((file) => file.sourceUrl), [skillId], "the skill is enabled");
2196
- assert.strictEqual(mockMatrixUtils.getRoomState(roomId, APP_BOXEL_ACTIVE_LLM)?.model, model, "the model is set");
2197
- assert.deepEqual(result.roomChanges, [`Enabled skills: ${skillId}`, `Model set to ${model}`]);
2198
- await command.execute({
2199
- realm: testRealmURL,
2200
- roomId,
2201
- code: `await room.disableSkills([${JSON.stringify(skillId)}]);`
2202
- });
2203
- skills = mockMatrixUtils.getRoomState(roomId, APP_BOXEL_ROOM_SKILLS_EVENT_TYPE);
2204
- assert.deepEqual(skills.enabledSkillCards, [], "the skill is disabled");
2205
- assert.deepEqual(skills.disabledSkillCards.map((file) => file.sourceUrl), [skillId]);
2206
- });
2207
- (0, import_qunit.test)("a run that fails makes no room change", async function(assert) {
2208
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2209
- await assert.rejects(command.execute({
2210
- realm: testRealmURL,
2211
- roomId,
2212
- code: `await room.enableSkills([${JSON.stringify(skillId)}]);
2213
- throw new Error('stop');`
2214
- }), /stop\. No file was saved\. The room changes it asked for were not made\./);
2215
- assert.notOk(mockMatrixUtils.getRoomEvents(roomId).some((event) => event.type === APP_BOXEL_ROOM_SKILLS_EVENT_TYPE), "the room skills are not changed");
2216
- });
2217
- (0, import_qunit.test)("room actions refuse a skill that does not exist and an unknown model", async function(assert) {
2218
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2219
- await assert.rejects(command.execute({
2220
- realm: testRealmURL,
2221
- roomId,
2222
- code: `await room.enableSkills([${JSON.stringify(`${testRealmURL}notes/first.md`)}]);`
2223
- }), /Not a skill card or skill markdown file/);
2224
- await assert.rejects(command.execute({
2225
- realm: testRealmURL,
2226
- roomId,
2227
- code: `await room.setModel('no-such/model');`
2228
- }), /Unknown model: no-such\/model/);
2229
- });
2230
- });
2231
- (0, import_qunit.test)("realm.ui actions run in order after the script finishes", async function(assert) {
2232
- let toolService = getService("tool-service");
2233
- let operatorModeStateService = getService("operator-mode-state-service");
2234
- let command = new RunRealmCodeTool(toolService.toolContext);
2235
- let result = await command.execute({
2236
- realm: testRealmURL,
2237
- roomId: "!room:example.com",
2238
- code: `let queued = await realm.ui.openFile('pet.gts');
2239
- await realm.ui.previewFormat('Pet/mango', 'fitted');
2240
- return queued;`
2241
- });
2242
- assert.deepEqual(JSON.parse(result.scriptResult), {
2243
- action: "openFile",
2244
- runs: "after the script finishes"
2245
- });
2246
- assert.deepEqual(result.uiActions.map(({ action, target, status }) => ({
2247
- action,
2248
- target,
2249
- status
2250
- })), [{
2251
- action: "openFile",
2252
- target: `${testRealmURL}pet.gts`,
2253
- status: "done"
2254
- }, {
2255
- action: "previewFormat",
2256
- target: `${testRealmURL}Pet/mango (fitted)`,
2257
- status: "done"
2258
- }]);
2259
- assert.strictEqual(operatorModeStateService.state.submode, "code");
2260
- assert.strictEqual(operatorModeStateService.state.codePath, `${testRealmURL}pet.gts`);
2261
- assert.strictEqual(operatorModeStateService.state.moduleInspector, "preview");
2262
- let selection = getService("playground-panel-service").getSelection(`${testRealmURL}pet/Pet`);
2263
- assert.strictEqual(selection?.cardId, `${testRealmURL}Pet/mango`);
2264
- assert.strictEqual(selection?.format, "fitted");
2265
- await command.execute({
2266
- realm: testRealmURL,
2267
- roomId: "!room:example.com",
2268
- code: `await realm.ui.switchSubmode('interact');`
2269
- });
2270
- assert.strictEqual(operatorModeStateService.state.submode, "interact");
2271
- });
2272
- (0, import_qunit.test)("realm.ui.previewFormat uses the base module of a card whose type comes from base", async function(assert) {
2273
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2274
- let baseModule = getService("network").virtualNetwork.toURL("@cardstack/base/card-api.gts").href;
2275
- let detail = (await command.execute({
2276
- realm: testRealmURL,
2277
- roomId: "!room:example.com",
2278
- code: `await realm.ui.previewFormat('Plain/base-typed', 'isolated');`
2279
- })).uiActions[0]?.detail ?? "";
2280
- assert.true(detail.includes(baseModule), `asks for ${baseModule}: ${detail}`);
2281
- assert.false(detail.includes(`${testRealmURL}Plain/`), "does not join the module to the instance path");
2282
- });
2283
- (0, import_qunit.test)("realm.ui opens a file the same run wrote", async function(assert) {
2284
- let toolService = getService("tool-service");
2285
- let operatorModeStateService = getService("operator-mode-state-service");
2286
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
2287
- realm: testRealmURL,
2288
- roomId: "!room:example.com",
2289
- code: `await realm.fs.writeText('notes/second.md', '# Second\\n');
2290
- await realm.ui.openFile('notes/second.md');`
2291
- });
2292
- assert.strictEqual(result.uiActions[0]?.status, "done");
2293
- assert.strictEqual(operatorModeStateService.state.codePath, `${testRealmURL}notes/second.md`);
2294
- });
2295
- (0, import_qunit.test)("realm.ui refuses a missing file, a path outside the realm, and a file that is not a card", async function(assert) {
2296
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2297
- let run = (code) => command.execute({
2298
- realm: testRealmURL,
2299
- roomId: "!room:example.com",
2300
- code
2301
- });
2302
- await assert.rejects(run(`await realm.ui.openFile('missing.gts');`), /File not found/);
2303
- await assert.rejects(run(`await realm.ui.openFile('../elsewhere.gts');`), /Path must be relative to the realm root/);
2304
- await assert.rejects(run(`await realm.ui.previewFormat('task', 'isolated');`), /Not a card instance/);
2305
- await assert.rejects(run(`await realm.ui.previewFormat('Pet/mango', 'head');`), /one of these formats/);
2306
- await assert.rejects(run(`await realm.ui.switchSubmode('host');`), /expects 'interact' or 'code'/);
2307
- });
2308
- (0, import_qunit.test)("a failed run does not do its realm.ui actions", async function(assert) {
2309
- let toolService = getService("tool-service");
2310
- let operatorModeStateService = getService("operator-mode-state-service");
2311
- let command = new RunRealmCodeTool(toolService.toolContext);
2312
- let submodeBefore = operatorModeStateService.state.submode;
2313
- await assert.rejects(command.execute({
2314
- realm: testRealmURL,
2315
- roomId: "!room:example.com",
2316
- code: `await realm.ui.openFile('pet.gts');
2317
- throw new Error('stop here');`
2318
- }), /stop here\. No file was saved\. The UI actions it asked for were not done\./);
2319
- assert.strictEqual(operatorModeStateService.state.submode, submodeBefore);
2320
- });
2321
- (0, import_qunit.module)("realm.cards.update", function() {
2322
- async function run(code) {
2323
- return await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2324
- realm: testRealmURL,
2325
- roomId: "!room:example.com",
2326
- code
2327
- });
2328
- }
2329
- async function cardJSON(path) {
2330
- let source = await getService("card-service").getSource(new URL(`${testRealmURL}${path}`));
2331
- return JSON.parse(source.content);
2332
- }
2333
- (0, import_qunit.test)("changes the fields it is given and keeps the others", async function(assert) {
2334
- let result = await run(`
2335
- const updated = await realm.cards.update('Recipe/pancakes', { cuisine: 'French' });
2336
- return updated;`);
2337
- assert.deepEqual(JSON.parse(result.scriptResult), {
2338
- path: "Recipe/pancakes.json",
2339
- fields: ["cuisine"],
2340
- saves: "after the script finishes"
2341
- });
2342
- assert.deepEqual(result.files.map((file) => [file.fileUrl, file.status]), [[`${testRealmURL}Recipe/pancakes.json`, "saved"]]);
2343
- let { data } = await cardJSON("Recipe/pancakes.json");
2344
- assert.strictEqual(data.attributes.cuisine, "French");
2345
- assert.strictEqual(data.attributes.name, "Pancakes");
2346
- assert.strictEqual(data.relationships.chef.links.self, "../Chef/ana", "links are kept");
2347
- });
2348
- (0, import_qunit.test)("saves the update to a realm named by a prefix-form identifier", async function(assert) {
2349
- let { virtualNetwork } = getService("network");
2350
- let testRealmPrefix = "@test/cards-update/";
2351
- virtualNetwork.addRealmMapping(testRealmPrefix, testRealmURL);
2352
- try {
2353
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2354
- realm: testRealmPrefix,
2355
- roomId: "!room:example.com",
2356
- code: `await realm.cards.update('Recipe/pancakes', { cuisine: 'Belgian' });`
2357
- });
2358
- assert.deepEqual(result.files.map((file) => file.status), ["saved"], "the update is saved");
2359
- let { data } = await cardJSON("Recipe/pancakes.json");
2360
- assert.strictEqual(data.attributes.cuisine, "Belgian");
2361
- } finally {
2362
- virtualNetwork.removeRealmMapping(testRealmPrefix);
2363
- }
2364
- });
2365
- (0, import_qunit.test)("edits a long text field in the script without cutting it", async function(assert) {
2366
- let long = Array.from({ length: 40 }, (_, n) => `Line ${n}: a \`code\` span, a \${placeholder} and "quotes".`).join("\n");
2367
- assert.true(long.length > 500);
2368
- await run(`await realm.cards.update('Pet/mango', { name: ${JSON.stringify(long)} });`);
2369
- let result = await run(`
2370
- const card = await realm.cards.get('Pet/mango');
2371
- const name = card.attributes.name.replace('Line 0:', 'First line:');
2372
- await realm.cards.update('Pet/mango', { name });
2373
- return name.length;`);
2374
- let expected = long.replace("Line 0:", "First line:");
2375
- assert.strictEqual(JSON.parse(result.scriptResult), expected.length);
2376
- let { data } = await cardJSON("Pet/mango.json");
2377
- assert.strictEqual(data.attributes.name, expected);
2378
- });
2379
- (0, import_qunit.test)("updates more cards than the file limit in one run, and saves them all", async function(assert) {
2380
- let cardService = getService("card-service");
2381
- for (let n = 0; n < 25; n++) await cardService.saveSource(new URL(`${testRealmURL}Recipe/batch/r${n}.json`), recipeJSON("Recipe", {
2382
- name: `R${n}`,
2383
- cuisine: "batch"
2384
- }, void 0, "../../recipe"), "editor");
2385
- let result = await run(`
2386
- for (let n = 0; n < 25; n++) {
2387
- await realm.cards.update('Recipe/batch/r' + n, { cuisine: 'done' });
2388
- }`);
2389
- assert.strictEqual(result.files.length, 25, "the result names each card");
2390
- for (let n of [0, 24]) {
2391
- let { data } = await cardJSON(`Recipe/batch/r${n}.json`);
2392
- assert.strictEqual(data.attributes.cuisine, "done");
2393
- assert.strictEqual(data.attributes.name, `R${n}`);
2394
- }
2395
- });
2396
- (0, import_qunit.test)("refuses an update that makes a card larger than the card size limit, counted in bytes", async function(assert) {
2397
- let result = await run(`
2398
- try {
2399
- await realm.cards.update('Pet/mango', { name: '\u{1F600}'.repeat(200000) });
2400
- } catch (error) {
2401
- return error.message;
2402
- }`);
2403
- assert.true(/Card is too large after this update: .*Pet\/mango\.json/.test(JSON.parse(result.scriptResult)), result.scriptResult);
2404
- assert.deepEqual(result.files, [], "nothing is saved");
2405
- });
2406
- (0, import_qunit.test)("two updates to the same card in one run both apply", async function(assert) {
2407
- let result = await run(`
2408
- await realm.cards.update('Recipe/ramen', { cuisine: 'Japanese street food' });
2409
- await realm.cards.update('Recipe/ramen.json', { name: 'Shoyu ramen' });`);
2410
- assert.strictEqual(result.files.length, 1);
2411
- let { data } = await cardJSON("Recipe/ramen.json");
2412
- assert.strictEqual(data.attributes.cuisine, "Japanese street food");
2413
- assert.strictEqual(data.attributes.name, "Shoyu ramen");
2414
- });
2415
- (0, import_qunit.test)("a run that fails saves no card update, and says so", async function(assert) {
2416
- await assert.rejects(run(`
2417
- await realm.cards.update('Recipe/pancakes', { cuisine: 'French' });
2418
- throw new Error('stop');`), /stop.*The card updates it asked for were not saved/);
2419
- let { data } = await cardJSON("Recipe/pancakes.json");
2420
- assert.strictEqual(data.attributes.cuisine, "unknown");
2421
- });
2422
- (0, import_qunit.test)("refuses a file that is not a card, attributes that are not an object, and realm.fs on an updated card", async function(assert) {
2423
- let result = await run(`
2424
- const errors = [];
2425
- for (const call of [
2426
- () => realm.cards.update('task.json', { title: 'x' }),
2427
- () => realm.cards.update('Recipe/missing', { name: 'x' }),
2428
- () => realm.cards.update('Recipe/pancakes', ['x']),
2429
- () => realm.cards.update('Recipe/pancakes', 'x'),
2430
- ]) {
2431
- try { await call(); } catch (error) { errors.push(error.message); }
2432
- }
2433
- await realm.cards.update('Recipe/ramen', { cuisine: 'Ramen-ya' });
2434
- try { await realm.fs.readText('Recipe/ramen.json'); } catch (error) { errors.push(error.message); }
2435
- return errors;`);
2436
- let errors = JSON.parse(result.scriptResult);
2437
- assert.true(/Not a card instance: .*task\.json/.test(errors[0]), errors[0]);
2438
- assert.true(/Card not found/.test(errors[1]), errors[1]);
2439
- assert.true(/attributes object/.test(errors[2]), errors[2]);
2440
- assert.true(/attributes object/.test(errors[3]), errors[3]);
2441
- assert.true(/realm\.fs cannot read or change it in the same run/.test(errors[4]), errors[4]);
2442
- let { data } = await cardJSON("Recipe/ramen.json");
2443
- assert.strictEqual(data.attributes.cuisine, "Ramen-ya");
2444
- });
2445
- });
2446
- (0, import_qunit.module)("realm.cards.search", function() {
2447
- const recipeRef = `{ module: ${JSON.stringify(`${testRealmURL}recipe`)}, name: 'Recipe' }`;
2448
- async function run(code) {
2449
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2450
- realm: testRealmURL,
2451
- roomId: "!room:example.com",
2452
- code
2453
- });
2454
- return {
2455
- result,
2456
- value: JSON.parse(result.scriptResult)
2457
- };
2458
- }
2459
- (0, import_qunit.test)("returns each card as plain data the script can use", async function(assert) {
2460
- let { result, value } = await run(`return await realm.cards.search({ filter: { eq: { name: 'Pancakes' }, on: ${recipeRef} } });`);
2461
- assert.deepEqual(result.files, [], "a search saves nothing");
2462
- assert.strictEqual(value.total, 1);
2463
- assert.false(value.truncated);
2464
- assert.strictEqual(value.cards.length, 1);
2465
- let [card] = value.cards;
2466
- assert.strictEqual(card.id, `${testRealmURL}Recipe/pancakes`);
2467
- assert.strictEqual(card.path, "Recipe/pancakes.json");
2468
- assert.deepEqual(card.type, {
2469
- module: `${testRealmURL}recipe`,
2470
- name: "Recipe"
2471
- });
2472
- assert.strictEqual(card.attributes.name, "Pancakes");
2473
- assert.strictEqual(card.attributes.cuisine, "unknown");
2474
- assert.strictEqual(card.attributes.cardTitle, "Recipe: Pancakes", "computed values come from the index");
2475
- assert.strictEqual(card.relationships.chef, `${testRealmURL}Chef/ana`, "a link is the full URL of the card it names");
2476
- });
2477
- (0, import_qunit.test)("a linksToMany field reports each link under its field path", async function(assert) {
2478
- let { value } = await run(`return (await realm.cards.search({ filter: { eq: { name: 'Ramen' }, on: ${recipeRef} } })).cards[0].relationships;`);
2479
- assert.strictEqual(value["helpers.0"], `${testRealmURL}Chef/ana`);
2480
- });
2481
- (0, import_qunit.test)("a script can search, then read and edit every card it found", async function(assert) {
2482
- let { result, value } = await run(`
2483
- const { cards } = await realm.cards.search({ filter: { eq: { cuisine: 'unknown' }, on: ${recipeRef} } });
2484
- for (const card of cards) {
2485
- await realm.fs.replace(card.path, '"cuisine": "unknown"', '"cuisine": "Italian"');
2486
- }
2487
- return cards.map((card) => card.path);`);
2488
- assert.deepEqual(value, ["Recipe/desserts/tiramisu.json", "Recipe/pancakes.json"]);
2489
- assert.deepEqual(result.files.map((file) => file.fileUrl), [`${testRealmURL}Recipe/desserts/tiramisu.json`, `${testRealmURL}Recipe/pancakes.json`]);
2490
- let source = await getService("card-service").getSource(new URL(`${testRealmURL}Recipe/desserts/tiramisu.json`));
2491
- assert.true(source.content.includes("\"cuisine\": \"Italian\""));
2492
- });
2493
- (0, import_qunit.test)("a type from a result is a type a query can search for", async function(assert) {
2494
- let { value } = await run(`
2495
- const { cards: [pancakes] } = await realm.cards.search({ filter: { eq: { name: 'Pancakes' }, on: ${recipeRef} } });
2496
- const { cards } = await realm.cards.search({ filter: { type: pancakes.type } });
2497
- return cards.map((card) => card.path);`);
2498
- assert.deepEqual(value, [
2499
- "Recipe/desserts/tiramisu.json",
2500
- "Recipe/pancakes.json",
2501
- "Recipe/ramen.json"
2502
- ]);
2503
- });
2504
- (0, import_qunit.test)("pages through the results and says when a page cut the list", async function(assert) {
2505
- let { value } = await run(`
2506
- const first = await realm.cards.search({ filter: { type: ${recipeRef} }, page: { size: 2 } });
2507
- const second = await realm.cards.search({ filter: { type: ${recipeRef} }, page: { size: 2, number: 1 } });
2508
- return { first, second };`);
2509
- assert.strictEqual(value.first.total, 3);
2510
- assert.true(value.first.truncated);
2511
- assert.deepEqual(value.first.cards.map((card) => card.path), ["Recipe/desserts/tiramisu.json", "Recipe/pancakes.json"]);
2512
- assert.false(value.second.truncated, "no card matches past the last page");
2513
- assert.deepEqual(value.second.cards.map((card) => card.path), ["Recipe/ramen.json"]);
2514
- });
2515
- (0, import_qunit.test)("searches only the realm the script runs in", async function(assert) {
2516
- let { value } = await run(`return (await realm.cards.search({ filter: { type: ${recipeRef} } })).cards.map((card) => card.id);`);
2517
- assert.false(value.some((id) => id.startsWith(otherRealmURL)), "another realm's cards are not returned");
2518
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2519
- await assert.rejects(command.execute({
2520
- realm: testRealmURL,
2521
- roomId: "!room:example.com",
2522
- code: `await realm.cards.search({ filter: { type: ${recipeRef} }, realms: [${JSON.stringify(otherRealmURL)}] });`
2523
- }), /realm\.cards\.search searches only this realm/);
2524
- });
2525
- (0, import_qunit.test)("an invalid query rejects, and a script that catches it carries on", async function(assert) {
2526
- let { value } = await run(`
2527
- let message;
2528
- try { await realm.cards.search({ filter: { type: ${recipeRef} }, limit: 10 }); } catch (e) { message = e.message; }
2529
- return { message, found: (await realm.cards.search({ filter: { type: ${recipeRef} } })).total };`);
2530
- assert.true(/unknown field in query: limit/.test(value.message), `the bad query was refused: ${value.message}`);
2531
- assert.strictEqual(value.found, 3, "the next search still ran");
2532
- });
2533
- (0, import_qunit.test)("a search does not count toward the file limit", async function(assert) {
2534
- let { value } = await run(`
2535
- await realm.cards.search({ filter: { type: ${recipeRef} } });
2536
- let found = 0;
2537
- for (let i = 0; i < 20; i++) {
2538
- if (!(await realm.fs.exists('missing-' + i + '.json'))) found++;
2539
- }
2540
- return found;`);
2541
- assert.strictEqual(value, 20);
2542
- });
2543
- (0, import_qunit.test)("a search a realm did not answer fails instead of finding nothing", async function(assert) {
2544
- let store = getService("store");
2545
- let searchEntries = store.searchEntries;
2546
- store.searchEntries = async () => ({
2547
- data: [],
2548
- meta: {
2549
- page: { total: 0 },
2550
- incomplete: true
2551
- }
2552
- });
2553
- try {
2554
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2555
- await assert.rejects(command.execute({
2556
- realm: testRealmURL,
2557
- roomId: "!room:example.com",
2558
- code: `await realm.cards.search({ filter: { type: ${recipeRef} } });`
2559
- }), /did not answer/);
2560
- } finally {
2561
- store.searchEntries = searchEntries;
2562
- }
2563
- });
2564
- });
2565
- });
2566
- var PATIENT_MODULE = `
2567
- import { contains, field, CardDef } from "@cardstack/base/card-api";
2568
- import StringField from "@cardstack/base/string";
2569
- import { operation, params } from "@cardstack/base/operations";
2570
-
2571
- export class Patient extends CardDef {
2572
- static displayName = 'Patient';
2573
- @field name = contains(StringField);
2574
- @field ward = contains(StringField);
2575
- @field lastVitals = contains(StringField);
2576
-
2577
- @operation static recordVitals = {
2578
- base: 'transform',
2579
- params: { reading: StringField },
2580
- set: { lastVitals: params('reading') },
2581
- };
2582
-
2583
- @operation static transferTo = {
2584
- base: 'transform',
2585
- params: { ward: StringField },
2586
- set: { ward: params('ward') },
2587
- };
2588
-
2589
- @operation static amend = { base: 'update' };
2590
-
2591
- @operation static chart = { base: 'read' };
2592
-
2593
- @operation static northWard = {
2594
- base: 'query',
2595
- query: { filter: { on: () => Patient, eq: { ward: 'north' } } },
2596
- };
2597
- }
2598
- `;
2599
- function patientFile(name, ward) {
2600
- return { data: {
2601
- type: "card",
2602
- attributes: {
2603
- name,
2604
- ward,
2605
- lastVitals: null
2606
- },
2607
- meta: { adoptsFrom: {
2608
- module: "../patient",
2609
- name: "Patient"
2610
- } }
2611
- } };
2612
- }
2613
- var readOnlyRealmURL = "http://test-realm/other/";
2614
- (0, import_qunit.module)("Integration | tools | run-realm-code | read-only workspace", function(hooks) {
2615
- setupRenderingTest(hooks);
2616
- setupLocalIndexing(hooks);
2617
- let mockMatrixUtils = setupMockMatrix(hooks, {
2618
- autostart: true,
2619
- activeRealms: [testRealmURL, readOnlyRealmURL],
2620
- realmPermissions: {
2621
- [testRealmURL]: ["read"],
2622
- [readOnlyRealmURL]: ["read"]
2623
- }
2624
- });
2625
- let captureRequests = [];
2626
- setupRealmServerEndpoints(hooks, [{
2627
- route: "_capture",
2628
- getResponse: async (req) => {
2629
- captureRequests.push(await req.clone().json());
2630
- return new Response(JSON.stringify({ data: {
2631
- type: "capture-result",
2632
- attributes: {
2633
- status: "ready",
2634
- base64: PNG_BASE64,
2635
- width: 1,
2636
- height: 1,
2637
- contentType: "image/png"
2638
- }
2639
- } }), {
2640
- status: 201,
2641
- headers: { "Content-Type": "application/vnd.api+json" }
2642
- });
2643
- }
2644
- }]);
2645
- setupRealmCacheTeardown(hooks);
2646
- let adapter;
2647
- hooks.beforeEach(async function() {
2648
- captureRequests = [];
2649
- await setupIntegrationTestRealm({
2650
- mockMatrixUtils,
2651
- realmURL: readOnlyRealmURL,
2652
- enforcePermissions: true,
2653
- permissions: { "*": ["read"] },
2654
- contents: { "brand.md": "# Brand\n" }
2655
- });
2656
- ({adapter} = await setupIntegrationTestRealm({
2657
- mockMatrixUtils,
2658
- enforcePermissions: true,
2659
- permissions: { "*": ["read"] },
2660
- contents: {
2661
- "task.json": "{ \"title\": \"Old title\" }\n",
2662
- "patient.gts": PATIENT_MODULE,
2663
- "Patient/ana.json": patientFile("Ana", "Cardiology"),
2664
- "notes/first.md": "# First\n",
2665
- "pet.gts": `
2666
- import { CardDef, field, contains } from '@cardstack/base/card-api';
2667
- import StringField from '@cardstack/base/string';
2668
-
2669
- export class Pet extends CardDef {
2670
- static displayName = 'Pet';
2671
- @field name = contains(StringField);
2672
- }
2673
- `,
2674
- "Pet/mango.json": { data: {
2675
- type: "card",
2676
- attributes: { name: "Mango" },
2677
- meta: { adoptsFrom: {
2678
- module: "../pet",
2679
- name: "Pet"
2680
- } }
2681
- } }
2682
- }
2683
- }));
2684
- await getService("realm").login(testRealmURL);
2685
- await getService("realm").login(readOnlyRealmURL);
2686
- });
2687
- (0, import_qunit.test)("realm.capture captures in a workspace the user can only read, and in another workspace by URL", async function(assert) {
2688
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2689
- realm: testRealmURL,
2690
- roomId: "!room:example.com",
2691
- code: `return [
2692
- await realm.capture('notes/first.md'),
2693
- await realm.capture('${readOnlyRealmURL}brand.md'),
2694
- ];`
2695
- });
2696
- assert.deepEqual(captureRequests.map((r) => r.data.attributes.fileURL), [`${testRealmURL}notes/first.md`, `${readOnlyRealmURL}brand.md`]);
2697
- assert.deepEqual(captureRequests.map((r) => r.data.attributes.realmURL), [testRealmURL, readOnlyRealmURL], "each capture is asked of the workspace that holds it");
2698
- assert.deepEqual(JSON.parse(result.scriptResult).map((c) => c.path), ["notes/first.md", `${readOnlyRealmURL}brand.md`], "a capture in another workspace is named by its URL");
2699
- assert.strictEqual(result.captures.length, 2);
2700
- });
2701
- (0, import_qunit.test)("a script reads a workspace the user can only read", async function(assert) {
2702
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2703
- realm: testRealmURL,
2704
- roomId: "!room:example.com",
2705
- code: `return {
2706
- text: await realm.fs.readText('task.json'),
2707
- exists: await realm.fs.exists('task.json'),
2708
- notes: await realm.fs.list('notes'),
2709
- };`
2710
- });
2711
- assert.deepEqual(result.files, [], "nothing is saved");
2712
- assert.deepEqual(JSON.parse(result.scriptResult), {
2713
- text: "{ \"title\": \"Old title\" }\n",
2714
- exists: true,
2715
- notes: [{
2716
- name: "first.md",
2717
- path: "notes/first.md",
2718
- kind: "file"
2719
- }]
2720
- });
2721
- });
2722
- (0, import_qunit.test)("a script searches a workspace the user can only read", async function(assert) {
2723
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2724
- realm: testRealmURL,
2725
- roomId: "!room:example.com",
2726
- code: `let found = await realm.cards.search({
2727
- filter: { type: { module: ${JSON.stringify(`${testRealmURL}pet`)}, name: 'Pet' } },
2728
- });
2729
- return { total: found.total, paths: found.cards.map((card) => card.path) };`
2730
- });
2731
- assert.deepEqual(result.files, [], "nothing is saved");
2732
- assert.deepEqual(JSON.parse(result.scriptResult), {
2733
- total: 1,
2734
- paths: ["Pet/mango.json"]
2735
- });
2736
- });
2737
- (0, import_qunit.test)("realm.operations is sent to the realm, which decides by its policy", async function(assert) {
2738
- getService("operations");
2739
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2740
- realm: testRealmURL,
2741
- roomId: "!room:example.com",
2742
- code: `try {
2743
- await realm.operations.invoke('Patient/ana', 'transferTo', { ward: 'ICU' });
2744
- return 'ran';
2745
- } catch (e) {
2746
- return e.message;
2747
- }`
2748
- });
2749
- let message = JSON.parse(result.scriptResult);
2750
- assert.notStrictEqual(message, "ran", "no policy grants the operation");
2751
- assert.notOk(/You can only read this workspace/.test(message), `the runner does not refuse it before the realm does: ${message}`);
2752
- });
2753
- (0, import_qunit.test)("each write is refused, and the script goes on", async function(assert) {
2754
- let toolService = getService("tool-service");
2755
- let cardService = getService("card-service");
2756
- let result = await new RunRealmCodeTool(toolService.toolContext).execute({
2757
- realm: testRealmURL,
2758
- roomId: "!room:example.com",
2759
- code: `let refused = [];
2760
- try { await realm.fs.writeText('new.json', '{}'); } catch (e) { refused.push(e.message); }
2761
- try { await realm.fs.replace('task.json', 'Old', 'New'); } catch (e) { refused.push(e.message); }
2762
- return { refused, text: await realm.fs.readText('task.json') };`
2763
- });
2764
- assert.deepEqual(result.files, [], "nothing is saved");
2765
- let { refused, text } = JSON.parse(result.scriptResult);
2766
- assert.strictEqual(refused.length, 2, "both writes are refused");
2767
- for (let message of refused) assert.true(/You can only read this workspace/.test(message), `the refusal says why: ${message}`);
2768
- assert.strictEqual(text, "{ \"title\": \"Old title\" }\n");
2769
- let source = await cardService.getSource(new URL(`${testRealmURL}new.json`));
2770
- assert.strictEqual(source.status, 404, "the new file is not in the realm");
2771
- });
2772
- (0, import_qunit.test)("a write the script does not catch fails the run, and the report says nothing was saved", async function(assert) {
2773
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2774
- await assert.rejects(command.execute({
2775
- realm: testRealmURL,
2776
- roomId: "!room:example.com",
2777
- code: `await realm.fs.writeText('new.json', '{}');`
2778
- }), /You can only read this workspace.*No file was saved/);
2779
- });
2780
- (0, import_qunit.test)("realm.index calls are refused", async function(assert) {
2781
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2782
- realm: testRealmURL,
2783
- roomId: "!room:example.com",
2784
- code: `let refused = [];
2785
- try { await realm.index.invalidate('task.json'); } catch (e) { refused.push(e.message); }
2786
- try { await realm.index.reindex(); } catch (e) { refused.push(e.message); }
2787
- return refused;`
2788
- });
2789
- let refused = JSON.parse(result.scriptResult);
2790
- assert.strictEqual(refused.length, 2, "both calls are refused");
2791
- for (let message of refused) assert.true(/You can only read this workspace/.test(message), `the refusal says why: ${message}`);
2792
- });
2793
- (0, import_qunit.test)("a card that is not indexed asks for a user who can write, not for a call the run would refuse", async function(assert) {
2794
- await adapter.write("Pet/unindexed.json", UNINDEXED_PET);
2795
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2796
- realm: testRealmURL,
2797
- roomId: "!room:example.com",
2798
- code: readCardScript("Pet/unindexed")
2799
- });
2800
- assert.strictEqual(JSON.parse(result.scriptResult), `Card is not indexed: ${testRealmURL}Pet/unindexed. Its file Pet/unindexed.json is in the workspace, and the workspace is not indexing, so reading the card again will not find it. You can only read this workspace, so tell the user that Pet/unindexed.json needs indexing again by someone who can write to it`);
2801
- });
2802
- });
2803
- (0, import_qunit.module)("Integration | tools | run-realm-code | images", function(hooks) {
2804
- setupRenderingTest(hooks);
2805
- setupLocalIndexing(hooks);
2806
- let mockMatrixUtils = setupMockMatrix(hooks, {
2807
- loggedInAs: "@testuser:localhost",
2808
- activeRealms: [testRealmURL],
2809
- autostart: true
2810
- });
2811
- const PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";
2812
- let imageRequests = [];
2813
- let abortedImageRequests = 0;
2814
- setupRealmServerEndpoints(hooks, [{
2815
- route: "_request-forward",
2816
- getResponse: async (req) => {
2817
- let body = await req.clone().json();
2818
- let request = JSON.parse(body.requestBody);
2819
- imageRequests.push({
2820
- url: body.url,
2821
- request
2822
- });
2823
- if (request.messages[0].content[0].text === "never answers") await new Promise((resolve, reject) => {
2824
- let fallback = setTimeout(resolve, 2e4);
2825
- let onAbort = () => {
2826
- clearTimeout(fallback);
2827
- abortedImageRequests += 1;
2828
- reject(new DOMException("aborted", "AbortError"));
2829
- };
2830
- if (req.signal.aborted) onAbort();
2831
- req.signal.addEventListener("abort", onAbort, { once: true });
2832
- });
2833
- return new Response(JSON.stringify({ choices: [{ message: {
2834
- content: "",
2835
- images: [{
2836
- type: "image_url",
2837
- image_url: { url: `data:image/png;base64,${PNG_BASE64}` }
2838
- }]
2839
- } }] }), {
2840
- status: 200,
2841
- headers: { "Content-Type": "application/json" }
2842
- });
2843
- }
2844
- }]);
2845
- setupRealmCacheTeardown(hooks);
2846
- hooks.beforeEach(async function() {
2847
- imageRequests = [];
2848
- abortedImageRequests = 0;
2849
- await setupIntegrationTestRealm({
2850
- mockMatrixUtils,
2851
- contents: {
2852
- "task.json": "{ \"title\": \"Old title\" }\n",
2853
- "photos/cat.jpg": "not really a jpeg"
2854
- }
2855
- });
2856
- });
2857
- (0, import_qunit.test)("a script that generates images always waits for the user, and gets more time", function(assert) {
2858
- let code = `await realm.images.generate({ prompt: 'a cat', path: 'cat.png' });`;
2859
- assert.true(RunRealmCodeTool.neverAutoExecutesFor({ code }), "a run that names realm.images.generate waits for a click");
2860
- assert.true(RunRealmCodeTool.extraExecuteTimeMsFor({ code }) > 0, "the tool service gives the run more time");
2861
- assert.strictEqual(RunRealmCodeTool.extraExecuteTimeMsFor({ code: `await realm.fs.writeText('a.json', '{}');` }), 0, "other runs keep the usual execute timeout");
2862
- });
2863
- (0, import_qunit.test)("realm.fs.delete removes an image the same run generated", async function(assert) {
2864
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2865
- realm: testRealmURL,
2866
- roomId: "!room:example.com",
2867
- code: `await realm.images.generate({ prompt: 'A small dot', path: 'images/dot.png' });
2868
- return {
2869
- deleted: await realm.fs.delete('images/dot.png'),
2870
- exists: await realm.fs.exists('images/dot.png'),
2871
- };`
2872
- });
2873
- assert.deepEqual(JSON.parse(result.scriptResult), {
2874
- deleted: {
2875
- path: "images/dot.png",
2876
- deleted: true
2877
- },
2878
- exists: false
2879
- });
2880
- assert.deepEqual(result.files.map((file) => [file.fileUrl, file.status]), [[`${testRealmURL}images/dot.png`, "deleted"]]);
2881
- });
2882
- (0, import_qunit.test)("realm.images.generate saves the image and returns its path", async function(assert) {
2883
- let toolService = getService("tool-service");
2884
- let network = getService("network");
2885
- let command = new RunRealmCodeTool(toolService.toolContext);
2886
- await command.execute({
2887
- realm: testRealmURL,
2888
- roomId: "!room:example.com",
2889
- code: `await realm.fs.writeBytes('source.png', ${JSON.stringify(PNG_BASE64)});`
2890
- });
2891
- let result = await command.execute({
2892
- realm: testRealmURL,
2893
- roomId: "!room:example.com",
2894
- code: `return await realm.images.generate({
2895
- prompt: 'A small dot',
2896
- path: 'images/dot',
2897
- sourceImageUrl: 'source.png',
2898
- llmModel: 'test/image-model',
2899
- });`
2900
- });
2901
- let expected = Uint8Array.from(atob(PNG_BASE64), (char) => char.charCodeAt(0));
2902
- assert.deepEqual(JSON.parse(result.scriptResult), {
2903
- path: "images/dot.png",
2904
- contentType: "image/png",
2905
- size: expected.byteLength,
2906
- saved: true
2907
- });
2908
- assert.deepEqual(result.files.map((file) => [file.fileUrl, file.status]), [[`${testRealmURL}images/dot.png`, "saved"]]);
2909
- assert.strictEqual(imageRequests.length, 1, "one image was requested");
2910
- let [{ request }] = imageRequests;
2911
- assert.strictEqual(request.model, "test/image-model");
2912
- assert.deepEqual(request.messages[0].content, [{
2913
- type: "text",
2914
- text: "A small dot"
2915
- }, {
2916
- type: "image_url",
2917
- image_url: { url: `data:image/png;base64,${PNG_BASE64}` }
2918
- }]);
2919
- let response = await network.authedFetch(new URL("images/dot.png", testRealmURL));
2920
- assert.deepEqual(Array.from(new Uint8Array(await response.arrayBuffer())), Array.from(expected), "the realm holds the image bytes");
2921
- });
2922
- (0, import_qunit.test)("realm.images.generate refuses a fifth image in one run", async function(assert) {
2923
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2924
- await assert.rejects(command.execute({
2925
- realm: testRealmURL,
2926
- roomId: "!room:example.com",
2927
- code: `for (let i = 1; i <= 5; i++) {
2928
- await realm.images.generate({ prompt: 'dot ' + i, path: 'dots/' + i + '.png' });
2929
- }`
2930
- }), /at most 4 images.*Files already saved by this run: .*dots\/4\.png/);
2931
- assert.strictEqual(imageRequests.length, 4, "four images were requested");
2932
- });
2933
- (0, import_qunit.test)("realm.images.generate refuses an existing file before it asks the model", async function(assert) {
2934
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2935
- await assert.rejects(command.execute({
2936
- realm: testRealmURL,
2937
- roomId: "!room:example.com",
2938
- code: `await realm.images.generate({ prompt: 'a task', path: 'task.json' });`
2939
- }), /File already exists/);
2940
- assert.strictEqual(imageRequests.length, 0, "no image was requested");
2941
- });
2942
- (0, import_qunit.test)("realm.images.generate refuses a path whose image may be saved over an existing file, before it asks the model", async function(assert) {
2943
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2944
- for (let path of ["photos/cat", "photos/cat.png"]) await assert.rejects(command.execute({
2945
- realm: testRealmURL,
2946
- roomId: "!room:example.com",
2947
- code: `await realm.images.generate({ prompt: 'a cat', path: '${path}' });`
2948
- }), /File already exists: .*photos\/cat\.jpg/, `${path} is refused`);
2949
- assert.strictEqual(imageRequests.length, 0, "no image was requested");
2950
- });
2951
- (0, import_qunit.test)("realm.images.generate takes one file slot per image", async function(assert) {
2952
- let result = await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
2953
- realm: testRealmURL,
2954
- roomId: "!room:example.com",
2955
- code: `for (let i = 1; i <= 16; i++) {
2956
- await realm.fs.exists('missing-' + i + '.json');
2957
- }
2958
- let paths = [];
2959
- for (let i = 1; i <= 4; i++) {
2960
- paths.push((await realm.images.generate({ prompt: 'dot ' + i, path: 'dots/' + i })).path);
2961
- }
2962
- return paths;`
2963
- });
2964
- assert.deepEqual(JSON.parse(result.scriptResult), [
2965
- "dots/1.png",
2966
- "dots/2.png",
2967
- "dots/3.png",
2968
- "dots/4.png"
2969
- ]);
2970
- });
2971
- (0, import_qunit.test)("realm.images.generate refuses a source image outside this realm", async function(assert) {
2972
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2973
- await assert.rejects(command.execute({
2974
- realm: testRealmURL,
2975
- roomId: "!room:example.com",
2976
- code: `await realm.images.generate({
2977
- prompt: 'a dot',
2978
- path: 'dot.png',
2979
- sourceImageUrl: 'http://other-realm.example/private/photo.png',
2980
- });`
2981
- }), /Path is outside this realm/);
2982
- assert.strictEqual(imageRequests.length, 0, "no image was requested");
2983
- });
2984
- (0, import_qunit.test)("an image request still in flight when the run ends is stopped", async function(assert) {
2985
- let cardService = getService("card-service");
2986
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
2987
- let started = Date.now();
2988
- await assert.rejects(command.execute({
2989
- realm: testRealmURL,
2990
- roomId: "!room:example.com",
2991
- code: `realm.images.generate({ prompt: 'never answers', path: 'late.png' });`
2992
- }), /await every realm call/);
2993
- assert.true(Date.now() - started < 15e3, "the run reports without waiting for the image");
2994
- if (imageRequests.length > 0) assert.strictEqual(abortedImageRequests, 1, "the image request was aborted");
2995
- await settled();
2996
- let source = await cardService.getSource(new URL(`${testRealmURL}late.png`));
2997
- assert.strictEqual(source.status, 404, "no image was saved");
2998
- });
2999
- (0, import_qunit.test)("a script that reaches realm.images.generate another way is refused", async function(assert) {
3000
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
3001
- let code = `let images = realm['ima' + 'ges'];
3002
- await images.generate({ prompt: 'a dot', path: 'dot.png' });`;
3003
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code }), "this run would not wait for a click");
3004
- await assert.rejects(command.execute({
3005
- realm: testRealmURL,
3006
- roomId: "!room:example.com",
3007
- code
3008
- }), /realm\.images\.generate must be called by that name/);
3009
- assert.strictEqual(imageRequests.length, 0, "no image was requested");
3010
- });
3011
- });
3012
- (0, import_qunit.module)("Integration | tools | run-realm-code | catalog-reuse", function(hooks) {
3013
- setupRenderingTest(hooks);
3014
- hooks.beforeEach(function() {
3015
- setCatalogRealmURL(getService("network").virtualNetwork.toURL("@cardstack/catalog/").href);
3016
- });
3017
- hooks.afterEach(function() {
3018
- resetCatalogRealmURL();
3019
- });
3020
- setupLocalIndexing(hooks);
3021
- let mockMatrixUtils = setupMockMatrix(hooks, {
3022
- loggedInAs: "@testuser:localhost",
3023
- activeRealms: [testRealmURL],
3024
- autostart: true
3025
- });
3026
- setupRealmCacheTeardown(hooks);
3027
- hooks.beforeEach(async function() {
3028
- await setupIntegrationTestRealm({
3029
- mockMatrixUtils,
3030
- contents: { "note.md": "# Note\n" }
3031
- });
3032
- });
3033
- (0, import_qunit.test)("realm.entries.search leaves the catalog out unless the room enabled catalog-reuse", async function(assert) {
3034
- await getService("matrix-service").ready;
3035
- let roomId = mockMatrixUtils.createAndJoinRoom({
3036
- sender: "@testuser:localhost",
3037
- name: "catalog-reuse"
3038
- });
3039
- let { virtualNetwork } = getService("network");
3040
- let sentRealms = [];
3041
- let spy = async (request) => {
3042
- if (new URL(request.url).pathname.endsWith("/_federated-search")) sentRealms.push(JSON.parse(await request.clone().text()).realms);
3043
- return null;
3044
- };
3045
- virtualNetwork.mount(spy, { prepend: true });
3046
- let catalogURL = virtualNetwork.toURL("@cardstack/catalog/").href;
3047
- try {
3048
- let realmServer = getService("realm-server");
3049
- await realmServer.ready;
3050
- let isCatalog = (realm) => realm === "@cardstack/catalog/" || realm === catalogURL;
3051
- assert.ok(realmServer.availableRealmIdentifiers.some(isCatalog), "the catalog is one of the available realms");
3052
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
3053
- let search = (code) => command.execute({
3054
- realm: testRealmURL,
3055
- roomId,
3056
- code
3057
- });
3058
- await search(`return await realm.entries.search({}, { realms: ['@cardstack/catalog/'] });`);
3059
- await search(`await realm.entries.search({}, { realms: ['@cardstack/catalog/', realm.current.url] });`);
3060
- await search(`await realm.entries.search({});`);
3061
- await search(`await realm.entries.search({}, { realms: [${JSON.stringify(`${catalogURL}components/`)}] });`);
3062
- assert.strictEqual(sentRealms.length, 2, "a search of the catalog alone, or of a folder in it, is answered empty, without a request");
3063
- assert.deepEqual(sentRealms[0], [testRealmURL], "a named catalog is dropped");
3064
- assert.notOk(sentRealms[1].some(isCatalog), "the default realms leave the catalog out");
3065
- mockMatrixUtils.simulateRemoteMessage(roomId, "@testuser:localhost", {
3066
- msgtype: "m.text",
3067
- body: "boxel-debug:feature:enable:catalog-reuse"
3068
- });
3069
- await settled();
3070
- await search(`await realm.entries.search({}, { realms: ['@cardstack/catalog/'] });`);
3071
- assert.deepEqual(sentRealms[2], ["@cardstack/catalog/"], "with the feature on, the catalog is searched");
3072
- } finally {
3073
- virtualNetwork.unmount(spy);
3074
- }
3075
- });
3076
- (0, import_qunit.test)("realm.entries.search records each search that reaches the catalog in client telemetry", async function(assert) {
3077
- await getService("matrix-service").ready;
3078
- let roomId = mockMatrixUtils.createAndJoinRoom({
3079
- sender: "@testuser:localhost",
3080
- name: "catalog-reuse"
3081
- });
3082
- let { virtualNetwork } = getService("network");
3083
- let catalogURL = virtualNetwork.toURL("@cardstack/catalog/").href;
3084
- let federatedSearch = async (request) => {
3085
- if (!new URL(request.url).pathname.endsWith("/_federated-search")) return null;
3086
- let body = await request.clone().text();
3087
- if (body.includes("boom")) return new Response("the catalog is down", { status: 500 });
3088
- let { realms } = JSON.parse(body);
3089
- let realmTotals = {};
3090
- let data = [];
3091
- let included = [];
3092
- let found = (id, readMe = "") => {
3093
- data.push({
3094
- type: "entry",
3095
- id,
3096
- relationships: { item: { data: {
3097
- type: "card",
3098
- id
3099
- } } }
3100
- });
3101
- included.push({
3102
- type: "card",
3103
- id,
3104
- attributes: { readMe }
3105
- });
3106
- };
3107
- for (let realm of realms) {
3108
- let url = virtualNetwork.toURL(realm).href;
3109
- if (url === catalogURL) {
3110
- if (body.includes("silent")) continue;
3111
- let huge = body.includes("huge");
3112
- realmTotals[url] = body.includes("kanban") ? 2 : huge ? 1 : 0;
3113
- if (realmTotals[url] > 0) found(`${catalogURL}Spec/board`, huge ? "x".repeat(11e5) : "");
3114
- } else if (url === testRealmURL) {
3115
- realmTotals[url] = body.includes("kanban") ? 1 : body.includes("notes") ? 3 : 0;
3116
- if (realmTotals[url] > 0) found(`${testRealmURL}note`);
3117
- } else realmTotals[url] = 0;
3118
- }
3119
- return new Response(JSON.stringify({
3120
- data,
3121
- included,
3122
- meta: {
3123
- page: { total: Object.values(realmTotals).reduce((a, b) => a + b, 0) },
3124
- realmTotals,
3125
- ...Object.keys(realmTotals).length < realms.length ? { incomplete: true } : {}
3126
- }
3127
- }), { headers: { "content-type": SupportedMimeType.CardJson } });
3128
- };
3129
- virtualNetwork.mount(federatedSearch, { prepend: true });
3130
- let telemetry = getService("client-telemetry");
3131
- let recorded = [];
3132
- let recordEvent = telemetry.recordEvent;
3133
- telemetry.recordEvent = (event) => {
3134
- recorded.push(event);
3135
- };
3136
- try {
3137
- await getService("realm-server").ready;
3138
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
3139
- let search = (matches, realms) => command.execute({
3140
- realm: testRealmURL,
3141
- roomId,
3142
- code: `await realm.entries.search(
3143
- {
3144
- filter: {
3145
- on: { module: '@cardstack/base/spec', name: 'Spec' },
3146
- matches: ${JSON.stringify(matches)},
3147
- },
3148
- },
3149
- { realms: ${realms} },
3150
- );`
3151
- });
3152
- await search("kanban", `['@cardstack/catalog/']`);
3153
- assert.deepEqual(recorded, [], "a search the feature gate keeps out of the catalog is not recorded");
3154
- mockMatrixUtils.simulateRemoteMessage(roomId, "@testuser:localhost", {
3155
- msgtype: "m.text",
3156
- body: "boxel-debug:feature:enable:catalog-reuse"
3157
- });
3158
- await waitUntil(() => getService("matrix-service").roomResources.get(roomId)?.events.some((event) => event.content?.body === "boxel-debug:feature:enable:catalog-reuse"));
3159
- await search("kanban board", `['@cardstack/catalog/']`);
3160
- await search("kanban", `['@cardstack/catalog/', realm.current.url]`);
3161
- await search("notes", "[]");
3162
- await search("kanban", "[realm.current.url]");
3163
- await assert.rejects(search("boom", `['@cardstack/catalog/']`), /the catalog is down/);
3164
- await search("silent", `['@cardstack/catalog/', realm.current.url]`);
3165
- await assert.rejects(search("huge", `['@cardstack/catalog/']`), /too large to return/);
3166
- let run = (code) => command.execute({
3167
- realm: testRealmURL,
3168
- roomId,
3169
- code
3170
- });
3171
- await assert.rejects(run(`await realm.entries.search({}, { realms: ['@cardstack/catalog/'], scope: 'card' });`), /Invalid scope "card"/);
3172
- await assert.rejects(run(`await realm.entries.search({}, { realms: ['@cardstack/catalog/', '@nope/realm/'] });`), /Unknown realm identifier "@nope\/realm\/"/);
3173
- await run(`await realm.entries.search(
3174
- {
3175
- filter: {
3176
- every: [
3177
- { matches: ${JSON.stringify(`${"x".repeat(298)}😀${"y".repeat(100)}`)} },
3178
- { not: { type: { module: '@cardstack/base/spec', name: 'Spec' } } },
3179
- ],
3180
- },
3181
- },
3182
- { realms: ['@cardstack/catalog/'] },
3183
- );`);
3184
- let spec = "@cardstack/base/spec#Spec";
3185
- let event = (fields) => ({
3186
- event_type: "catalog-search",
3187
- tool: "run-realm-code",
3188
- query_type: spec,
3189
- error: "",
3190
- realm: testRealmURL,
3191
- ...fields
3192
- });
3193
- let [named, beside, everyRealm, failed, unanswered, tooLarge, excluding, ...rest] = recorded;
3194
- assert.deepEqual(named, event({
3195
- query_text: "kanban board",
3196
- total: 2,
3197
- returned: 1
3198
- }), "a search that names the catalog is recorded with what it found");
3199
- assert.deepEqual(beside, event({
3200
- query_text: "kanban",
3201
- total: 2,
3202
- returned: 1
3203
- }), "only what the catalog matched is counted, not the realm searched beside it");
3204
- assert.deepEqual(everyRealm, event({
3205
- query_text: "notes",
3206
- total: 0,
3207
- returned: 0
3208
- }), "a search of every realm that matched only workspace cards found nothing in the catalog");
3209
- let { error, ...failedRest } = failed;
3210
- assert.deepEqual({
3211
- ...failedRest,
3212
- error: ""
3213
- }, event({
3214
- query_text: "boom",
3215
- total: null,
3216
- returned: null
3217
- }), "a search that threw is recorded without counts");
3218
- assert.true(error.includes("the catalog is down"), `the error is recorded: ${error}`);
3219
- assert.deepEqual(unanswered, event({
3220
- query_text: "silent",
3221
- total: null,
3222
- returned: null,
3223
- error: "a catalog realm did not answer"
3224
- }), "a catalog that did not answer is recorded as a failure, not as finding nothing");
3225
- assert.deepEqual(tooLarge, event({
3226
- query_text: "huge",
3227
- total: 1,
3228
- returned: 1,
3229
- error: `The entry ${catalogURL}Spec/board is too large to return from a search`
3230
- }), "an answer too large to return keeps its counts and records why the script got nothing");
3231
- assert.deepEqual(excluding, event({
3232
- query_text: `${"x".repeat(298)}😀…`,
3233
- query_type: "",
3234
- total: 0,
3235
- returned: 0
3236
- }), "a type the query excludes is not the type it searched for, and long text is cut without splitting a character");
3237
- assert.deepEqual(rest, [], "a search of another realm only, or one refused before it was sent, is not recorded");
3238
- } finally {
3239
- telemetry.recordEvent = recordEvent;
3240
- virtualNetwork.unmount(federatedSearch);
3241
- }
3242
- });
3243
- (0, import_qunit.test)("realm.cards.search in the catalog finds nothing unless the room enabled catalog-reuse", async function(assert) {
3244
- await getService("matrix-service").ready;
3245
- let roomId = mockMatrixUtils.createAndJoinRoom({
3246
- sender: "@testuser:localhost",
3247
- name: "catalog-reuse"
3248
- });
3249
- let { virtualNetwork } = getService("network");
3250
- let catalogURL = virtualNetwork.toURL("@cardstack/catalog/").href;
3251
- let searches = 0;
3252
- let catalog = async (request) => {
3253
- let { pathname } = new URL(request.url);
3254
- if (request.url === `${catalogURL}_info`) return new Response(JSON.stringify({ data: {
3255
- id: catalogURL,
3256
- type: "realm-info",
3257
- attributes: { name: "Catalog" }
3258
- } }), { headers: {
3259
- "content-type": SupportedMimeType.RealmInfo,
3260
- "x-boxel-realm-public-readable": "true"
3261
- } });
3262
- if (pathname.endsWith("_search") || pathname.endsWith("_federated-search")) {
3263
- searches++;
3264
- return new Response(JSON.stringify({
3265
- data: [],
3266
- meta: { page: { total: 0 } }
3267
- }), { headers: { "content-type": SupportedMimeType.CardJson } });
3268
- }
3269
- return null;
3270
- };
3271
- virtualNetwork.mount(catalog, { prepend: true });
3272
- try {
3273
- await getService("realm").ensureRealmMeta(catalogURL);
3274
- let command = new RunRealmCodeTool(getService("tool-service").toolContext);
3275
- let search = async () => JSON.parse((await command.execute({
3276
- realm: "@cardstack/catalog/",
3277
- roomId,
3278
- code: `return await realm.cards.search({});`
3279
- })).scriptResult);
3280
- assert.deepEqual(await search(), {
3281
- cards: [],
3282
- total: 0,
3283
- truncated: false
3284
- }, "the catalog answers empty");
3285
- assert.strictEqual(searches, 0, "without a request");
3286
- mockMatrixUtils.simulateRemoteMessage(roomId, "@testuser:localhost", {
3287
- msgtype: "m.text",
3288
- body: "boxel-debug:feature:enable:catalog-reuse"
3289
- });
3290
- await waitUntil(() => getService("matrix-service").roomResources.get(roomId)?.events.some((event) => event.content?.body === "boxel-debug:feature:enable:catalog-reuse"));
3291
- await search();
3292
- assert.strictEqual(searches, 1, "with the feature on, it is searched");
3293
- } finally {
3294
- virtualNetwork.unmount(catalog);
3295
- }
3296
- });
3297
- });
3298
- (0, import_qunit.module)("Integration | tools | run-realm-code | research", function(hooks) {
3299
- setupRenderingTest(hooks);
3300
- setupLocalIndexing(hooks);
3301
- let mockMatrixUtils = setupMockMatrix(hooks, {
3302
- loggedInAs: "@testuser:localhost",
3303
- activeRealms: [testRealmURL],
3304
- autostart: true
3305
- });
3306
- let forwarded = [];
3307
- let answer;
3308
- setupRealmServerEndpoints(hooks, [{
3309
- route: "_request-forward",
3310
- getResponse: async (req) => {
3311
- let body = await req.clone().json();
3312
- let request = {
3313
- url: body.url,
3314
- request: JSON.parse(body.requestBody)
3315
- };
3316
- forwarded.push(request);
3317
- return answer(request);
3318
- }
3319
- }]);
3320
- setupRealmCacheTeardown(hooks);
3321
- function json(body, status = 200) {
3322
- return new Response(JSON.stringify(body), {
3323
- status,
3324
- headers: { "Content-Type": "application/json" }
3325
- });
3326
- }
3327
- function chat(content, extra = {}) {
3328
- return json({
3329
- model: "openai/gpt-4.1-mini",
3330
- choices: [{
3331
- finish_reason: "stop",
3332
- message: {
3333
- content,
3334
- ...extra
3335
- }
3336
- }]
3337
- });
3338
- }
3339
- const RECIPE_SCHEMA = {
3340
- type: "object",
3341
- additionalProperties: false,
3342
- required: ["title", "servings"],
3343
- properties: {
3344
- title: { type: "string" },
3345
- servings: {
3346
- type: "integer",
3347
- minimum: 1
3348
- }
3349
- }
3350
- };
3351
- async function run(code) {
3352
- return await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
3353
- realm: testRealmURL,
3354
- roomId: "!room:example.com",
3355
- code
3356
- });
3357
- }
3358
- hooks.beforeEach(async function() {
3359
- forwarded = [];
3360
- answer = () => json({ error: { message: "no answer set" } }, 500);
3361
- await setupIntegrationTestRealm({
3362
- mockMatrixUtils,
3363
- contents: { "task.json": "{ \"title\": \"Old title\" }\n" }
3364
- });
3365
- });
3366
- (0, import_qunit.test)("research calls need no click, and a run that names one gets more time", function(assert) {
3367
- for (let code of [
3368
- `await realm.web.search('chili recipe');`,
3369
- `await realm.web.read('https://example.com/');`,
3370
- `await realm.resolve({});`
3371
- ]) {
3372
- assert.false(RunRealmCodeTool.neverAutoExecutesFor({ code }), `no click for ${code}`);
3373
- assert.true(RunRealmCodeTool.extraExecuteTimeMsFor({ code }) > 0, `more time for ${code}`);
3374
- }
3375
- });
3376
- (0, import_qunit.test)("realm.web.search returns the url_citation sources of an Exa search", async function(assert) {
3377
- answer = () => chat("Here are some chili recipes.", { annotations: [
3378
- {
3379
- type: "url_citation",
3380
- url_citation: {
3381
- url: "https://www.budgetbytes.com/chili/",
3382
- title: "Chili - Budget Bytes",
3383
- content: "A classic beef chili."
3384
- }
3385
- },
3386
- {
3387
- type: "url_citation",
3388
- url_citation: {
3389
- url: "https://www.budgetbytes.com/chili/",
3390
- title: "Duplicate",
3391
- content: "Duplicate"
3392
- }
3393
- },
3394
- {
3395
- type: "file",
3396
- file: { name: "ignored" }
3397
- },
3398
- {
3399
- type: "url_citation",
3400
- url_citation: { url: "https://example.com/chili" }
3401
- }
3402
- ] });
3403
- let result = await run(`return await realm.web.search('beef chili recipe', { limit: 3, includeDomains: ['BudgetBytes.com'] });`);
3404
- assert.deepEqual(JSON.parse(result.scriptResult), [{
3405
- url: "https://www.budgetbytes.com/chili/",
3406
- title: "Chili - Budget Bytes",
3407
- snippet: "A classic beef chili."
3408
- }, {
3409
- url: "https://example.com/chili",
3410
- title: "",
3411
- snippet: ""
3412
- }]);
3413
- assert.strictEqual(forwarded.length, 1, "one request was forwarded");
3414
- let [{ url, request }] = forwarded;
3415
- assert.strictEqual(url, "https://openrouter.ai/api/v1/chat/completions");
3416
- assert.deepEqual(request.plugins, [{
3417
- id: "web",
3418
- engine: "exa",
3419
- max_results: 3,
3420
- include_domains: ["budgetbytes.com"]
3421
- }]);
3422
- assert.strictEqual(request.messages.at(-1).content, "beef chili recipe", "the query is the user message");
3423
- assert.strictEqual(result.activity.length, 1, "the search is in the run activity");
3424
- assert.true(/Exa searched for "beef chili recipe".*2 results/.test(result.activity[0]), result.activity[0]);
3425
- });
3426
- (0, import_qunit.test)("realm.web.search refuses a limit outside 1 to 10 without a request", async function(assert) {
3427
- await assert.rejects(run(`await realm.web.search('chili', { limit: 11 });`), /limit must be a whole number from 1 to 10/);
3428
- assert.strictEqual(forwarded.length, 0, "nothing was forwarded");
3429
- });
3430
- (0, import_qunit.test)("realm.web.read returns the page markdown, capped, with its metadata", async function(assert) {
3431
- let markdown = "# Chili\n" + "x".repeat(7e4);
3432
- answer = () => json({
3433
- success: true,
3434
- data: {
3435
- markdown,
3436
- metadata: {
3437
- title: "Chili",
3438
- statusCode: 200,
3439
- contentType: "text/html; charset=utf-8",
3440
- sourceURL: "https://www.budgetbytes.com/chili/",
3441
- ogImage: "https://www.budgetbytes.com/chili.jpg"
3442
- }
3443
- }
3444
- });
3445
- let result = await run(`let page = await realm.web.read('https://www.budgetbytes.com/chili/');
3446
- return { url: page.url, length: page.markdown.length, start: page.markdown.slice(0, 7), truncated: page.truncated, metadata: page.metadata };`);
3447
- assert.deepEqual(JSON.parse(result.scriptResult), {
3448
- url: "https://www.budgetbytes.com/chili/",
3449
- length: 64e3,
3450
- start: "# Chili",
3451
- truncated: true,
3452
- metadata: {
3453
- statusCode: 200,
3454
- contentType: "text/html; charset=utf-8",
3455
- title: "Chili",
3456
- sourceURL: "https://www.budgetbytes.com/chili/"
3457
- }
3458
- });
3459
- let [{ url, request }] = forwarded;
3460
- assert.strictEqual(url, "https://api.firecrawl.dev/v2/scrape");
3461
- assert.strictEqual(request.url, "https://www.budgetbytes.com/chili/");
3462
- assert.deepEqual(request.formats, ["markdown"]);
3463
- assert.true(request.onlyMainContent, "main content by default");
3464
- assert.deepEqual(result.activity, ["Firecrawl read www.budgetbytes.com"]);
3465
- });
3466
- (0, import_qunit.test)("realm.web.read throws with the status and Firecrawl’s reason", async function(assert) {
3467
- answer = ({ request }) => request.url.endsWith(".svg") ? json({
3468
- success: false,
3469
- code: "SCRAPE_UNSUPPORTED_FILE_ERROR",
3470
- error: "The file type is not supported."
3471
- }, 400) : json({
3472
- success: false,
3473
- error: "This website is no longer supported, we do not support this site."
3474
- }, 403);
3475
- let result = await run(`let errors = [];
3476
- for (let url of ['https://www.seriouseats.com/chili', 'https://example.com/logo.svg']) {
3477
- try {
3478
- await realm.web.read(url);
3479
- } catch (error) {
3480
- errors.push(error.message);
3481
- }
3482
- }
3483
- return errors;`);
3484
- let [site, svg] = JSON.parse(result.scriptResult);
3485
- assert.true(/HTTP 403/.test(site), site);
3486
- assert.true(/we do not support this site/.test(site), site);
3487
- assert.true(/HTTP 400/.test(svg), svg);
3488
- assert.true(/SCRAPE_UNSUPPORTED_FILE_ERROR/.test(svg), svg);
3489
- assert.strictEqual(result.activity.length, 2);
3490
- assert.true(/^Firecrawl could not read www\.seriouseats\.com: .*we do not support this site/.test(result.activity[0]), result.activity[0]);
3491
- });
3492
- (0, import_qunit.test)("an uncaught realm.web.read failure fails the run with the reason", async function(assert) {
3493
- answer = () => json({
3494
- success: false,
3495
- error: "we do not support this site"
3496
- }, 403);
3497
- await assert.rejects(run(`await realm.web.read('https://www.seriouseats.com/chili');`), /HTTP 403: we do not support this site/);
3498
- });
3499
- (0, import_qunit.test)("realm.resolve returns JSON that matches outputSchema", async function(assert) {
3500
- answer = () => chat("{\"title\":\"Beef Chili\",\"servings\":6}");
3501
- let result = await run(`return await realm.resolve({
3502
- instruction: 'Normalize this recipe header.',
3503
- input: { name: ' beef chili ', serves: 'six' },
3504
- error: 'servings must be a number',
3505
- outputSchema: ${JSON.stringify(RECIPE_SCHEMA)},
3506
- });`);
3507
- assert.deepEqual(JSON.parse(result.scriptResult), {
3508
- output: {
3509
- title: "Beef Chili",
3510
- servings: 6
3511
- },
3512
- model: "openai/gpt-4.1-mini"
3513
- });
3514
- let [{ request }] = forwarded;
3515
- assert.deepEqual(request.response_format.json_schema.schema, RECIPE_SCHEMA);
3516
- assert.true(request.response_format.json_schema.strict, "strict output");
3517
- assert.deepEqual(JSON.parse(request.messages[1].content), {
3518
- instruction: "Normalize this recipe header.",
3519
- input: {
3520
- name: " beef chili ",
3521
- serves: "six"
3522
- },
3523
- error: "servings must be a number"
3524
- });
3525
- });
3526
- (0, import_qunit.test)("realm.resolve refuses an answer that does not match outputSchema", async function(assert) {
3527
- answer = () => chat("{\"title\":\"Beef Chili\",\"servings\":0,\"notes\":\"x\"}");
3528
- await assert.rejects(run(`await realm.resolve({
3529
- instruction: 'Normalize this recipe header.',
3530
- input: { name: 'beef chili' },
3531
- outputSchema: ${JSON.stringify(RECIPE_SCHEMA)},
3532
- });`), /does not match outputSchema/);
3533
- });
3534
- (0, import_qunit.test)("realm.resolve refuses an open schema without a request", async function(assert) {
3535
- await assert.rejects(run(`await realm.resolve({
3536
- instruction: 'Normalize this.',
3537
- input: { name: 'beef chili' },
3538
- outputSchema: { type: 'object', properties: { title: { type: 'string' } }, required: ['title'] },
3539
- });`), /additionalProperties must be false/);
3540
- assert.strictEqual(forwarded.length, 0, "nothing was forwarded");
3541
- });
3542
- (0, import_qunit.test)("realm.resolve may be called at most 3 times per run", async function(assert) {
3543
- answer = () => chat("{\"title\":\"Chili\",\"servings\":4}");
3544
- let result = await run(`let outcomes = [];
3545
- for (let i = 0; i < 4; i++) {
3546
- try {
3547
- await realm.resolve({
3548
- instruction: 'Normalize this recipe header.',
3549
- input: { i },
3550
- outputSchema: ${JSON.stringify(RECIPE_SCHEMA)},
3551
- });
3552
- outcomes.push('ok');
3553
- } catch (error) {
3554
- outcomes.push(error.message);
3555
- }
3556
- }
3557
- return outcomes;`);
3558
- let outcomes = JSON.parse(result.scriptResult);
3559
- assert.deepEqual(outcomes.slice(0, 3), [
3560
- "ok",
3561
- "ok",
3562
- "ok"
3563
- ]);
3564
- assert.true(/at most 3 times per run/.test(outcomes[3]), outcomes[3]);
3565
- assert.strictEqual(forwarded.length, 3, "three requests were forwarded");
3566
- });
3567
- (0, import_qunit.test)("realm.resolve refuses a request for code, and an answer that holds code", async function(assert) {
3568
- await assert.rejects(run(`await realm.resolve({
3569
- instruction: 'Write a JavaScript function that parses this recipe.',
3570
- input: { name: 'beef chili' },
3571
- outputSchema: ${JSON.stringify(RECIPE_SCHEMA)},
3572
- });`), /does not write code, scripts, markup or commands/);
3573
- assert.strictEqual(forwarded.length, 0, "no model was asked");
3574
- answer = () => chat("{\"title\":\"<script>alert(1)<\/script>\",\"servings\":4}");
3575
- await assert.rejects(run(`await realm.resolve({
3576
- instruction: 'Normalize this recipe header.',
3577
- input: { name: 'beef chili' },
3578
- outputSchema: ${JSON.stringify(RECIPE_SCHEMA)},
3579
- });`), /the answer looked like code/);
3580
- });
3581
- (0, import_qunit.test)("realm.resolve takes data instructions and answers that only share words with code", async function(assert) {
3582
- answer = () => chat(JSON.stringify({
3583
- title: "Create an account first => then <b>log in</b>",
3584
- servings: 4
3585
- }));
3586
- for (let instruction of [
3587
- "Update the prices to USD.",
3588
- "Normalize each address and return the ISO country code.",
3589
- "Export the recipe header as a title and a serving count."
3590
- ]) {
3591
- let result = await run(`return await realm.resolve({
3592
- instruction: ${JSON.stringify(instruction)},
3593
- input: { name: 'beef chili' },
3594
- outputSchema: ${JSON.stringify(RECIPE_SCHEMA)},
3595
- });`);
3596
- assert.strictEqual(JSON.parse(result.scriptResult).output.servings, 4, `answered: ${instruction}`);
3597
- }
3598
- });
3599
- (0, import_qunit.test)("realm.web.search takes maxResults as an alias of limit, and includeContent", async function(assert) {
3600
- answer = () => chat("Sources.", { annotations: [{
3601
- type: "url_citation",
3602
- url_citation: {
3603
- url: "https://example.com/a",
3604
- title: "A",
3605
- content: "y".repeat(3e3)
3606
- }
3607
- }, {
3608
- type: "url_citation",
3609
- url_citation: {
3610
- url: "http://192.168.1.10/private",
3611
- title: "B"
3612
- }
3613
- }] });
3614
- let result = await run(`let [found] = await realm.web.search('logos', { maxResults: 2, includeContent: true, tbs: 'qdr:m' });
3615
- return { count: (await realm.web.search('logos', { limit: 2, maxResults: 2 })).length, snippet: found.snippet.length, content: found.content.length };`);
3616
- assert.deepEqual(JSON.parse(result.scriptResult), {
3617
- count: 1,
3618
- snippet: 1e3,
3619
- content: 3e3
3620
- });
3621
- assert.strictEqual(forwarded[0].request.plugins[0].max_results, 2);
3622
- assert.true(forwarded[0].request.messages.at(-1).content.includes("qdr:m"), "the time filter reaches the model");
3623
- await assert.rejects(run(`await realm.web.search('logos', { limit: 2, maxResults: 3 });`), /limit and maxResults must match/);
3624
- });
3625
- (0, import_qunit.test)("realm.web.read refuses local and private-network URLs without a request", async function(assert) {
3626
- for (let url of [
3627
- "http://localhost:4201/base/",
3628
- "http://192.168.1.10/",
3629
- "https://user:secret@example.com/"
3630
- ]) await assert.rejects(run(`await realm.web.read('${url}');`), /cannot read URLs with credentials, local hosts or private-network addresses/, url);
3631
- assert.strictEqual(forwarded.length, 0, "nothing was forwarded");
3632
- });
3633
- (0, import_qunit.test)("realm.activity records the steps of a multi-step script", async function(assert) {
3634
- let result = await run(`await realm.activity({ message: 'Gather sources', current: 2, total: 4 });
3635
- await realm.activity({ message: 'Write the card', phase: 'write' });
3636
- return 1;`);
3637
- assert.deepEqual(result.activity, ["Step 2 of 4 · Gather sources", "Write the card (write)"]);
3638
- await assert.rejects(run(`await realm.activity({ message: 'Too far', current: 5, total: 4 });`), /current cannot be more than total/);
3639
- });
3640
- (0, import_qunit.test)("realm.plan names the steps ahead, and activity counts inside one", async function(assert) {
3641
- let result = await run(`await realm.plan(['Search calendars', 'Read each page', 'Compare']);
3642
- await realm.activity({ message: 'Read each page', current: 2, total: 3, count: 3, of: 5 });
3643
- return 1;`);
3644
- assert.deepEqual(result.activity, ["Plan · Search calendars · Read each page · Compare", "Step 2 of 3 · Read each page"]);
3645
- await assert.rejects(run(`await realm.plan([]);`), /realm.plan expects 1 to 12 step names/);
3646
- await assert.rejects(run(`await realm.activity({ message: 'Read', current: 1, total: 2, count: 6, of: 5 });`), /count cannot be more than of/);
3647
- });
3648
- function answerFixes(fix) {
3649
- answer = ({ request }) => {
3650
- let { code } = JSON.parse(request.messages[1].content);
3651
- return chat(JSON.stringify({
3652
- fixedCode: fix(code),
3653
- summary: "added a missing ']'"
3654
- }));
3655
- };
3656
- }
3657
- const BROKEN = `let items = [1, 2, 3;
3658
- return items.length;`;
3659
- (0, import_qunit.test)("auto-fix patches a missing bracket and the run completes", async function(assert) {
3660
- answerFixes((code) => code.replace("3;", "3];"));
3661
- let result = await run(BROKEN);
3662
- assert.strictEqual(result.scriptResult, "3", "the fixed script ran");
3663
- assert.strictEqual(forwarded.length, 1, "one model call");
3664
- let [{ url, request }] = forwarded;
3665
- assert.strictEqual(url, "https://openrouter.ai/api/v1/chat/completions");
3666
- assert.strictEqual(request.model, "openai/gpt-4.1-mini");
3667
- let sent = JSON.parse(request.messages[1].content);
3668
- assert.strictEqual(sent.code, BROKEN, "the model gets the script");
3669
- assert.strictEqual(sent.error.name, "SyntaxError");
3670
- assert.strictEqual(result.activity.length, 1);
3671
- assert.true(/^Fixed a SyntaxError( at line \d+)?: added a missing '\]' \(auto-fix by openai\/gpt-4\.1-mini\)$/.test(result.activity[0]), result.activity[0]);
3672
- assert.strictEqual(result.scriptFixes.length, 1);
3673
- assert.true(result.scriptFixes[0].includes("- let items = [1, 2, 3;\n+ let items = [1, 2, 3];"), result.scriptFixes[0]);
3674
- });
3675
- (0, import_qunit.test)("auto-fix fixes a ReferenceError thrown before any realm call", async function(assert) {
3676
- answerFixes((code) => code.replace("itmes", "items"));
3677
- let result = await run(`let items = [1, 2];
3678
- return itmes.length;`);
3679
- assert.strictEqual(result.scriptResult, "2");
3680
- assert.strictEqual(forwarded.length, 1);
3681
- });
3682
- (0, import_qunit.test)("a script that runs cleanly makes no auto-fix call", async function(assert) {
3683
- let result = await run(`return 1 + 1;`);
3684
- assert.strictEqual(result.scriptResult, "2");
3685
- assert.strictEqual(forwarded.length, 0, "no model call");
3686
- assert.deepEqual(result.scriptFixes, []);
3687
- });
3688
- (0, import_qunit.test)("an error after a realm call is not auto-fixed", async function(assert) {
3689
- answerFixes((code) => code.replace("notDefined()", "null"));
3690
- await assert.rejects(run(`await realm.fs.exists('task.json');
3691
- notDefined();`), /ReferenceError/);
3692
- assert.strictEqual(forwarded.length, 0, "no model call");
3693
- });
3694
- (0, import_qunit.test)("a fix that adds a realm call is rejected", async function(assert) {
3695
- answerFixes((code) => code.replace("3;", "3];\nawait realm.fs.exists('task.json');"));
3696
- await assert.rejects(run(BROKEN), /SyntaxError[\s\S]*rejected the fix: the fix added realm\.fs\.exists/);
3697
- assert.strictEqual(forwarded.length, 1);
3698
- });
3699
- (0, import_qunit.test)("a fix that changes the arguments of a realm call is rejected", async function(assert) {
3700
- answerFixes((code) => code.replace("3;", "3];").replace("delete('draft.json')", "delete('index.json')"));
3701
- await assert.rejects(run(`let items = [1, 2, 3;
3702
- await realm.fs.delete('draft.json');`), /rejected the fix: the fix changed a line that uses realm or room/);
3703
- });
3704
- (0, import_qunit.test)("a fix that changes too much is rejected", async function(assert) {
3705
- answerFixes((code) => code.replace("3;", `3];\n${"items.push(0);\n".repeat(8)}`));
3706
- await assert.rejects(run(BROKEN), /rejected the fix: the fix changed more than 5 lines/);
3707
- });
3708
- (0, import_qunit.test)("auto-fix stops after its attempt cap", async function(assert) {
3709
- answerFixes((code) => code.includes("3;") ? code.replace("3;", "3}") : code.replace("3}", "3;"));
3710
- await assert.rejects(run(BROKEN), /SyntaxError[\s\S]*auto-fixed the script/);
3711
- assert.strictEqual(forwarded.length, 2, "two fixes were asked for");
3712
- });
3713
- });
3714
- (0, import_qunit.module)("Integration | tools | run-realm-code | realm.operations", function(hooks) {
3715
- setupRenderingTest(hooks);
3716
- setupLocalIndexing(hooks);
3717
- let mockMatrixUtils = setupMockMatrix(hooks, {
3718
- loggedInAs: "@testuser:localhost",
3719
- activeRealms: [testRealmURL],
3720
- autostart: true
3721
- });
3722
- setupRealmCacheTeardown(hooks);
3723
- let adapter;
3724
- hooks.beforeEach(async function() {
3725
- ({adapter} = await setupIntegrationTestRealm({
3726
- mockMatrixUtils,
3727
- contents: {
3728
- "patient.gts": PATIENT_MODULE,
3729
- "Patient/ana.json": patientFile("Ana", "Cardiology"),
3730
- "Patient/ben.json": patientFile("Ben", "Cardiology"),
3731
- "Patient/cleo.json": patientFile("Cleo", "Cardiology"),
3732
- "Patient/dev.json": patientFile("Dev", "Oncology")
3733
- }
3734
- }));
3735
- await getService("realm").login(testRealmURL);
3736
- getService("operations");
3737
- });
3738
- async function run(code) {
3739
- return await new RunRealmCodeTool(getService("tool-service").toolContext).execute({
3740
- realm: testRealmURL,
3741
- roomId: "!room:example.com",
3742
- code
3743
- });
3744
- }
3745
- async function attributesOf(path) {
3746
- let file = await adapter.openFile(path);
3747
- return JSON.parse(file.content).data.attributes;
3748
- }
3749
- (0, import_qunit.test)("realm.operations.invoke runs an operation the type declares", async function(assert) {
3750
- let result = await run(`
3751
- return await realm.operations.invoke('Patient/ana', 'transferTo', { ward: 'ICU' });`);
3752
- let answer = JSON.parse(result.scriptResult);
3753
- assert.strictEqual(answer.path, "Patient/ana.json");
3754
- assert.strictEqual(answer.operation, "transferTo");
3755
- assert.strictEqual(answer.id, `${testRealmURL}Patient/ana`);
3756
- assert.ok(answer.version, "the answer has the version the card now holds");
3757
- assert.strictEqual((await attributesOf("Patient/ana.json")).ward, "ICU");
3758
- });
3759
- (0, import_qunit.test)("realm.operations.invokeBatchOperation updates many patients in one batch", async function(assert) {
3760
- let result = await run(`
3761
- let found = await realm.cards.search({
3762
- filter: {
3763
- on: { module: ${JSON.stringify(`${testRealmURL}patient`)}, name: 'Patient' },
3764
- eq: { ward: 'Cardiology' },
3765
- },
3766
- });
3767
- let answers = await realm.operations.invokeBatchOperation(
3768
- found.cards.map((patient) => ({
3769
- path: patient.path,
3770
- operation: 'recordVitals',
3771
- payload: { reading: 'HR 72, BP 120/80' },
3772
- })),
3773
- );
3774
- return answers.map((answer) => answer.path).sort();`);
3775
- assert.deepEqual(JSON.parse(result.scriptResult), [
3776
- "Patient/ana.json",
3777
- "Patient/ben.json",
3778
- "Patient/cleo.json"
3779
- ]);
3780
- for (let path of [
3781
- "Patient/ana.json",
3782
- "Patient/ben.json",
3783
- "Patient/cleo.json"
3784
- ]) assert.strictEqual((await attributesOf(path)).lastVitals, "HR 72, BP 120/80", `${path} has the reading`);
3785
- assert.strictEqual((await attributesOf("Patient/dev.json")).lastVitals, null, "a patient of another ward is not changed");
3786
- });
3787
- (0, import_qunit.test)("a batch with one bad entry changes no card", async function(assert) {
3788
- let result = await run(`
3789
- try {
3790
- await realm.operations.invokeBatchOperation([
3791
- { path: 'Patient/ana', operation: 'recordVitals', payload: { reading: 'HR 80' } },
3792
- { path: 'Patient/ben', operation: 'recordVitals', payload: {} },
3793
- ]);
3794
- return 'ran';
3795
- } catch (e) {
3796
- return e.message;
3797
- }`);
3798
- assert.strictEqual(JSON.parse(result.scriptResult), "operation \"recordVitals\" requires a value for params(\"reading\")");
3799
- assert.strictEqual((await attributesOf("Patient/ana.json")).lastVitals, null);
3800
- });
3801
- (0, import_qunit.test)("an update-based operation patches the card, alone and in a batch", async function(assert) {
3802
- await run(`
3803
- await realm.operations.invoke('Patient/ana', 'amend', { attributes: { name: 'Ana B' } });
3804
- await realm.operations.invokeBatchOperation([
3805
- { path: 'Patient/ben', operation: 'amend', payload: { attributes: { name: 'Ben C' } } },
3806
- { path: 'Patient/cleo', operation: 'recordVitals', payload: { reading: 'HR 64' } },
3807
- ]);`);
3808
- assert.strictEqual((await attributesOf("Patient/ana.json")).name, "Ana B");
3809
- assert.strictEqual((await attributesOf("Patient/ben.json")).name, "Ben C");
3810
- assert.strictEqual((await attributesOf("Patient/cleo.json")).lastVitals, "HR 64");
3811
- });
3812
- (0, import_qunit.test)("a read-based operation answers the document", async function(assert) {
3813
- let result = await run(`
3814
- let answer = await realm.operations.invoke('Patient/ana', 'chart');
3815
- return { path: answer.path, id: answer.id, name: answer.document.data.attributes.name };`);
3816
- assert.deepEqual(JSON.parse(result.scriptResult), {
3817
- path: "Patient/ana.json",
3818
- name: "Ana"
3819
- });
3820
- });
3821
- (0, import_qunit.test)("an operation the type does not declare is refused with the ones it does", async function(assert) {
3822
- let result = await run(`
3823
- try {
3824
- await realm.operations.invoke('Patient/ana', 'discharge');
3825
- return 'ran';
3826
- } catch (e) {
3827
- return e.message;
3828
- }`);
3829
- assert.strictEqual(JSON.parse(result.scriptResult), "\"discharge\" is not an operation Patient declares. It declares: amend, chart, recordVitals, transferTo");
3830
- });
3831
- (0, import_qunit.test)("a query the type declares is refused with where to search instead", async function(assert) {
3832
- let result = await run(`
3833
- try {
3834
- await realm.operations.invoke('Patient/ana', 'northWard');
3835
- return 'ran';
3836
- } catch (e) {
3837
- return e.message;
3838
- }`);
3839
- let message = JSON.parse(result.scriptResult);
3840
- assert.true(message.startsWith("\"northWard\" is a query operation"), `the refusal says what the name is: ${message}`);
3841
- assert.true(message.includes("realm.cards.search"), `and where results are read instead: ${message}`);
3842
- });
3843
- });
3844
- //#endregion