@jxsuite/studio 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/canvas.html +21 -0
  2. package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
  3. package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
  4. package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
  5. package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
  6. package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
  7. package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
  8. package/dist/chunks/content-source-34gnkbnn.js +38 -0
  9. package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
  10. package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
  11. package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
  12. package/dist/chunks/extension-sections-6mqydz35.js +301 -0
  13. package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
  14. package/dist/chunks/files-8kn321h1.js +70 -0
  15. package/dist/chunks/files-8kn321h1.js.map +9 -0
  16. package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
  17. package/dist/chunks/git-panel-tjbr191d.js +51 -0
  18. package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
  19. package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
  20. package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
  21. package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
  22. package/dist/chunks/layers-panel-87pb25km.js +58 -0
  23. package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
  24. package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
  25. package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
  26. package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
  27. package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
  28. package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
  29. package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
  30. package/dist/chunks/right-panel-zpdxd98t.js +37 -0
  31. package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
  32. package/dist/chunks/section-registry-zmckaxf4.js +30 -0
  33. package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
  34. package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
  35. package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
  36. package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
  37. package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
  38. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
  39. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
  40. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
  41. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
  42. package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
  43. package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
  44. package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
  45. package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
  46. package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
  47. package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
  48. package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
  49. package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
  50. package/dist/chunks/studio-41exgzhq.js +6690 -0
  51. package/dist/chunks/studio-41exgzhq.js.map +38 -0
  52. package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
  53. package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
  54. package/dist/chunks/studio-50k77cca.js +1787 -0
  55. package/dist/chunks/studio-50k77cca.js.map +18 -0
  56. package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
  57. package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
  58. package/dist/chunks/studio-6f0am8f2.js +53 -0
  59. package/dist/chunks/studio-6f0am8f2.js.map +10 -0
  60. package/dist/chunks/studio-6nmjc5qk.js +7002 -0
  61. package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
  62. package/dist/chunks/studio-7afd21nw.js +67 -0
  63. package/dist/chunks/studio-7afd21nw.js.map +10 -0
  64. package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
  65. package/dist/chunks/studio-7bmdvzne.js.map +10 -0
  66. package/dist/chunks/studio-8jpzqk5s.js +128 -0
  67. package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
  68. package/dist/chunks/studio-94m77tgk.js +1482 -0
  69. package/dist/chunks/studio-94m77tgk.js.map +13 -0
  70. package/dist/chunks/studio-9je6w5sq.js +1000 -0
  71. package/dist/chunks/studio-9je6w5sq.js.map +16 -0
  72. package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
  73. package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
  74. package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
  75. package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
  76. package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
  77. package/dist/chunks/studio-bw5dz6km.js +608 -0
  78. package/dist/chunks/studio-bw5dz6km.js.map +21 -0
  79. package/dist/chunks/studio-c6s5getc.js +4232 -0
  80. package/dist/chunks/studio-c6s5getc.js.map +39 -0
  81. package/dist/chunks/studio-cjm7fdjf.js +451 -0
  82. package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
  83. package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
  84. package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
  85. package/dist/chunks/studio-dg7zyt5x.js +28 -0
  86. package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
  87. package/dist/chunks/studio-dzcyvvvz.js +166 -0
  88. package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
  89. package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
  90. package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
  91. package/dist/chunks/studio-f12h6177.js +411 -0
  92. package/dist/chunks/studio-f12h6177.js.map +13 -0
  93. package/dist/chunks/studio-hbp1s8m9.js +1817 -0
  94. package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
  95. package/dist/chunks/studio-k2sxjph5.js +15295 -0
  96. package/dist/chunks/studio-k2sxjph5.js.map +235 -0
  97. package/dist/chunks/studio-myje51t3.js +385 -0
  98. package/dist/chunks/studio-myje51t3.js.map +12 -0
  99. package/dist/chunks/studio-na6rwzhw.js +353 -0
  100. package/dist/chunks/studio-na6rwzhw.js.map +11 -0
  101. package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
  102. package/dist/chunks/studio-p471gg5n.js.map +14 -0
  103. package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
  104. package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
  105. package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
  106. package/dist/chunks/studio-sas7mt3k.js +75 -0
  107. package/dist/chunks/studio-sas7mt3k.js.map +10 -0
  108. package/dist/chunks/studio-t5wqwzdh.js +74 -0
  109. package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
  110. package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
  111. package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
  112. package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
  113. package/dist/chunks/studio-tr20m8g8.js.map +9 -0
  114. package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
  115. package/dist/chunks/studio-v96qfnww.js.map +54 -0
  116. package/dist/chunks/studio-vcetc91k.js +659 -0
  117. package/dist/chunks/studio-vcetc91k.js.map +10 -0
  118. package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
  119. package/dist/chunks/studio-vmymjefp.js.map +98 -0
  120. package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
  121. package/dist/chunks/studio-x9hmy5kr.js +390 -0
  122. package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
  123. package/dist/chunks/studio-xa0ce0n7.js +335 -0
  124. package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
  125. package/dist/chunks/studio-xm3dbxvn.js +378 -0
  126. package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
  127. package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
  128. package/dist/chunks/studio-zv37yrfa.js +1054 -0
  129. package/dist/chunks/studio-zv37yrfa.js.map +13 -0
  130. package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
  131. package/dist/chunks/ws-client-654ts66j.js.map +11 -0
  132. package/dist/iframe-entry.js +668 -230
  133. package/dist/studio.js +21080 -32585
  134. package/index.html +35 -4685
  135. package/package.json +17 -15
  136. package/src/about/about-modal.ts +42 -11
  137. package/src/browse/library-commands.ts +240 -0
  138. package/src/browse/library-layouts.ts +369 -0
  139. package/src/browse/library-model.ts +396 -0
  140. package/src/browse/library-pane.ts +1049 -0
  141. package/src/browse/library-preview.ts +252 -0
  142. package/src/browse/library-source.ts +150 -0
  143. package/src/canvas/canvas-helpers.ts +33 -9
  144. package/src/canvas/canvas-live-render.ts +45 -29
  145. package/src/canvas/canvas-patcher.ts +151 -31
  146. package/src/canvas/canvas-perf.ts +46 -7
  147. package/src/canvas/canvas-render.ts +1092 -220
  148. package/src/canvas/canvas-surface.ts +240 -0
  149. package/src/canvas/canvas-utils.ts +1166 -124
  150. package/src/canvas/iframe-drop.ts +2 -1
  151. package/src/canvas/iframe-entry.ts +241 -4
  152. package/src/canvas/iframe-host.ts +1226 -143
  153. package/src/canvas/iframe-inline-edit.ts +31 -0
  154. package/src/canvas/iframe-interaction.ts +76 -16
  155. package/src/canvas/iframe-keys.ts +107 -45
  156. package/src/canvas/iframe-overlay.ts +38 -1
  157. package/src/canvas/iframe-protocol.ts +137 -2
  158. package/src/canvas/iframe-render.ts +70 -2
  159. package/src/canvas/iframe-slash.ts +6 -0
  160. package/src/canvas/path-mapping.ts +56 -6
  161. package/src/canvas/surface-registry.ts +292 -0
  162. package/src/collab/collab-commands.ts +244 -0
  163. package/src/collab/collab-session.ts +198 -32
  164. package/src/collab/collab-state.ts +28 -2
  165. package/src/collab/presence-chips.ts +100 -9
  166. package/src/commands/active-registry.ts +42 -0
  167. package/src/commands/app-commands.ts +176 -0
  168. package/src/commands/budget.ts +158 -0
  169. package/src/commands/command-args.ts +253 -0
  170. package/src/commands/context.ts +387 -0
  171. package/src/commands/defaults.ts +580 -0
  172. package/src/commands/keymap.ts +571 -0
  173. package/src/commands/levels.ts +345 -0
  174. package/src/commands/live-context.ts +193 -0
  175. package/src/commands/reference.ts +227 -0
  176. package/src/commands/registry.ts +293 -0
  177. package/src/component-props.ts +3 -2
  178. package/src/content/draft-state.ts +106 -0
  179. package/src/content/entry-commands.ts +282 -0
  180. package/src/content/entry-editor.ts +327 -0
  181. package/src/content/entry-fields.ts +116 -0
  182. package/src/content/entry-model.ts +175 -0
  183. package/src/editor/canvas-context-menu.ts +17 -11
  184. package/src/editor/canvas-slash-bridge.ts +11 -4
  185. package/src/editor/context-menu.ts +804 -204
  186. package/src/editor/convert-to-component.ts +31 -10
  187. package/src/editor/convert-to-repeater.ts +3 -2
  188. package/src/editor/inline-edit-apply.ts +5 -5
  189. package/src/editor/inline-edit.ts +86 -50
  190. package/src/editor/insert-zone-action.ts +1 -1
  191. package/src/editor/shortcuts.ts +1043 -329
  192. package/src/editor/slash-menu.ts +1 -0
  193. package/src/files/elements.ts +166 -0
  194. package/src/files/file-ops.ts +178 -31
  195. package/src/files/files.ts +898 -268
  196. package/src/files/fs-events.ts +21 -0
  197. package/src/files/media-meta.ts +203 -0
  198. package/src/files/media-paths.ts +141 -0
  199. package/src/files/media-upload.ts +7 -3
  200. package/src/files/media-usage.ts +189 -0
  201. package/src/github/github-auth.ts +235 -33
  202. package/src/github/github-publish.ts +80 -21
  203. package/src/grid/grid-controller.ts +152 -12
  204. package/src/grid/grid-layout.ts +225 -20
  205. package/src/grid/grid-open.ts +120 -0
  206. package/src/grid/grid-panel.ts +554 -39
  207. package/src/grid/grid-source.ts +27 -1
  208. package/src/grid/redirects-grid.ts +599 -0
  209. package/src/grid/redirects.ts +398 -0
  210. package/src/grid/sources/content-source.ts +108 -2
  211. package/src/i18n/i18n-commands.ts +322 -0
  212. package/src/new-project/add-repo-modal.ts +8 -10
  213. package/src/new-project/import-tab.ts +7 -0
  214. package/src/new-project/location-fields.ts +9 -1
  215. package/src/new-project/new-project-modal.ts +221 -245
  216. package/src/packages/jxsuite-update.ts +97 -48
  217. package/src/packages/pull-package-sync.ts +18 -9
  218. package/src/page-params.ts +2 -1
  219. package/src/panels/activity-bar.ts +152 -91
  220. package/src/panels/activity-panel.ts +481 -0
  221. package/src/panels/ai-chat/chat-markdown.ts +8 -3
  222. package/src/panels/ai-chat/chat-view.ts +245 -18
  223. package/src/panels/ai-chat/composer.ts +31 -5
  224. package/src/panels/ai-chat/sessions-view.ts +17 -10
  225. package/src/panels/ai-panel.ts +279 -53
  226. package/src/panels/block-action-bar.ts +1115 -224
  227. package/src/panels/bottom-dock.ts +337 -0
  228. package/src/panels/canvas-dnd-bridge.ts +37 -8
  229. package/src/panels/chat-panel.ts +29 -12
  230. package/src/panels/data-explorer.ts +254 -112
  231. package/src/panels/data-grid.ts +10 -4
  232. package/src/panels/dnd.ts +28 -51
  233. package/src/panels/editors.ts +434 -107
  234. package/src/panels/elements-panel.ts +66 -2
  235. package/src/panels/empty-state.ts +112 -0
  236. package/src/panels/events-panel.ts +596 -82
  237. package/src/panels/formula-workspace.ts +408 -218
  238. package/src/panels/frontmatter-fields.ts +51 -10
  239. package/src/panels/frontmatter-panel.ts +357 -79
  240. package/src/panels/git-panel.ts +375 -164
  241. package/src/panels/head-panel.ts +791 -85
  242. package/src/panels/i18n-panel.ts +592 -0
  243. package/src/panels/imports-panel.ts +95 -85
  244. package/src/panels/jump-bar.ts +584 -0
  245. package/src/panels/layers-panel.ts +1106 -328
  246. package/src/panels/left-panel.ts +109 -204
  247. package/src/panels/navigator-panels.ts +131 -0
  248. package/src/panels/overlays.ts +7 -2
  249. package/src/panels/pane-context.ts +1477 -0
  250. package/src/panels/pane-grid.ts +406 -0
  251. package/src/panels/panel-registry.ts +340 -0
  252. package/src/panels/panel-scheduler.ts +75 -0
  253. package/src/panels/problems-panel.ts +234 -0
  254. package/src/panels/properties-panel.ts +946 -1139
  255. package/src/panels/provenance.ts +258 -0
  256. package/src/panels/quick-search.ts +791 -122
  257. package/src/panels/right-panel.ts +228 -102
  258. package/src/panels/seo-modal.ts +395 -0
  259. package/src/panels/settings-pane.ts +203 -0
  260. package/src/panels/signals-panel.ts +354 -137
  261. package/src/panels/statement-editor.ts +41 -25
  262. package/src/panels/statusbar.ts +342 -106
  263. package/src/panels/style-panel.ts +974 -463
  264. package/src/panels/style-utils.ts +3 -3
  265. package/src/panels/stylebook-doc.ts +4 -2
  266. package/src/panels/stylebook-layers-panel.ts +3 -2
  267. package/src/panels/stylebook-panel.ts +51 -26
  268. package/src/panels/tab-strip.ts +1058 -78
  269. package/src/panels/target-line.ts +274 -0
  270. package/src/panels/toolbar.ts +631 -484
  271. package/src/panels/welcome-screen.ts +301 -198
  272. package/src/platform-errors.ts +26 -3
  273. package/src/platform.ts +96 -2
  274. package/src/platforms/cloud.ts +71 -8
  275. package/src/platforms/devserver.ts +92 -29
  276. package/src/publish/deploy-checklist.ts +383 -0
  277. package/src/publish/pages-service.ts +10 -1
  278. package/src/publish/publish-commands.ts +218 -0
  279. package/src/publish/publish-panel.ts +110 -16
  280. package/src/recent-projects.ts +3 -2
  281. package/src/services/a11y-report.ts +505 -0
  282. package/src/services/ai-models.ts +30 -1
  283. package/src/services/ai-project-tools.ts +29 -10
  284. package/src/services/ai-system-prompt.ts +53 -14
  285. package/src/services/ai-tools.ts +39 -3
  286. package/src/services/ai-writes.ts +154 -0
  287. package/src/services/announce.ts +97 -0
  288. package/src/services/automation.ts +424 -175
  289. package/src/services/cem-export.ts +9 -4
  290. package/src/services/clock.ts +61 -0
  291. package/src/services/document-assistant.ts +36 -8
  292. package/src/services/idle.ts +179 -0
  293. package/src/services/import-client.ts +26 -0
  294. package/src/services/monaco-buffer.ts +627 -0
  295. package/src/services/monaco-lazy.ts +36 -0
  296. package/src/services/notify.ts +271 -0
  297. package/src/services/profile.ts +155 -0
  298. package/src/services/references.ts +0 -0
  299. package/src/services/token-lint.ts +3 -2
  300. package/src/services/tool-executor.ts +53 -7
  301. package/src/services/trusted-types.ts +123 -0
  302. package/src/settings/contexts-section.ts +427 -0
  303. package/src/settings/contributed-section.ts +149 -11
  304. package/src/settings/css-vars-editor.ts +306 -349
  305. package/src/settings/defs-editor.ts +93 -34
  306. package/src/settings/dependencies-editor.ts +7 -7
  307. package/src/settings/extension-sections.ts +37 -5
  308. package/src/settings/general-settings.ts +204 -121
  309. package/src/settings/locales-section.ts +347 -0
  310. package/src/settings/preferences-accounts.ts +140 -0
  311. package/src/settings/preferences-dialog.ts +620 -0
  312. package/src/settings/preferences-keymap.ts +270 -0
  313. package/src/settings/project-sections.ts +260 -0
  314. package/src/settings/section-registry.ts +169 -0
  315. package/src/settings/settings-document.ts +385 -0
  316. package/src/shell.ts +1549 -0
  317. package/src/site-context.ts +45 -20
  318. package/src/state.ts +14 -275
  319. package/src/store.ts +88 -43
  320. package/src/studio.ts +790 -346
  321. package/src/style/live-preview.ts +36 -0
  322. package/src/style/project-styles.ts +349 -0
  323. package/src/style/token-ref.ts +123 -0
  324. package/src/tabs/patch-ops.ts +16 -4
  325. package/src/tabs/project-config.ts +416 -0
  326. package/src/tabs/selection.ts +323 -0
  327. package/src/tabs/tab.ts +182 -47
  328. package/src/tabs/transact.ts +209 -28
  329. package/src/types.ts +68 -13
  330. package/src/ui/ai-credentials-form.ts +39 -35
  331. package/src/ui/ai-managed-connect.ts +7 -1
  332. package/src/ui/dynamic-slot.ts +224 -81
  333. package/src/ui/expression-editor.ts +71 -63
  334. package/src/ui/field-input.ts +4 -6
  335. package/src/ui/field-row.ts +215 -38
  336. package/src/ui/form-controls.ts +194 -7
  337. package/src/ui/layers.ts +492 -69
  338. package/src/ui/media-picker.ts +115 -25
  339. package/src/ui/panel-resize.ts +109 -91
  340. package/src/ui/progress-modal.ts +131 -50
  341. package/src/ui/regions.ts +462 -0
  342. package/src/ui/schema-form.ts +229 -45
  343. package/src/ui/spectrum.ts +24 -8
  344. package/src/ui/timing.ts +49 -0
  345. package/src/ui/value-selector.ts +20 -0
  346. package/src/ui/value-source.ts +348 -0
  347. package/src/ui/virtual-window.ts +400 -0
  348. package/src/utils/edit-display.ts +3 -2
  349. package/src/utils/inherited-style.ts +67 -37
  350. package/src/view.ts +64 -78
  351. package/src/workspace/pane-derive.ts +1258 -0
  352. package/src/workspace/session.ts +317 -0
  353. package/src/workspace/workspace.ts +1345 -23
  354. package/styles/canvas.css +653 -0
  355. package/styles/forced-colors.css +106 -0
  356. package/styles/inspector.css +1454 -0
  357. package/styles/overlays.css +2704 -0
  358. package/styles/panels.css +1701 -0
  359. package/styles/shell.css +1423 -0
  360. package/styles/tokens.css +151 -0
  361. package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
  362. package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
  363. package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
  364. package/dist/chunks/files-j8a1t06k.js +0 -50
  365. package/dist/chunks/files-j8a1t06k.js.map +0 -9
  366. package/dist/chunks/git-panel-xtq5z81x.js +0 -28
  367. package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
  368. package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
  369. package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
  370. package/dist/chunks/settings-modal-17ttr96g.js +0 -29
  371. package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
  372. package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
  373. package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
  374. package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
  375. package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
  376. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
  377. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
  378. package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
  379. package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
  380. package/dist/chunks/studio-0xgs7xrs.js +0 -429
  381. package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
  382. package/dist/chunks/studio-4d8hzcz5.js +0 -3427
  383. package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
  384. package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
  385. package/dist/chunks/studio-9smfzqhc.js +0 -19
  386. package/dist/chunks/studio-9smfzqhc.js.map +0 -10
  387. package/dist/chunks/studio-jm0z592w.js.map +0 -115
  388. package/dist/chunks/studio-m2t4mdg5.js +0 -1854
  389. package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
  390. package/dist/chunks/studio-n4p11dfy.js +0 -853
  391. package/dist/chunks/studio-n4p11dfy.js.map +0 -12
  392. package/dist/chunks/studio-qkvt37c0.js.map +0 -9
  393. package/dist/chunks/studio-sjh1wt1a.js +0 -3744
  394. package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
  395. package/dist/chunks/studio-v7jkjqng.js.map +0 -46
  396. package/dist/chunks/studio-xq0t7n5t.js +0 -140
  397. package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
  398. package/dist/chunks/studio-xze4zrs1.js.map +0 -10
  399. package/dist/chunks/studio-yfcstdzy.js +0 -399
  400. package/dist/chunks/studio-yfcstdzy.js.map +0 -12
  401. package/dist/chunks/studio-zp7jncs8.js +0 -469
  402. package/dist/chunks/studio-zp7jncs8.js.map +0 -14
  403. package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
  404. package/src/browse/browse-modal.ts +0 -69
  405. package/src/browse/browse.ts +0 -904
  406. package/src/canvas/canvas-diff.ts +0 -216
  407. package/src/canvas/nested-site-style.ts +0 -58
  408. package/src/new-project/design-fields.ts +0 -264
  409. package/src/new-project/templates.ts +0 -61
  410. package/src/panels/tab-bar.ts +0 -548
  411. package/src/settings/settings-modal.ts +0 -203
  412. /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
  413. /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
  414. /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
  415. /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
  416. /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
  417. /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
  418. /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
  419. /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
@@ -3,9 +3,16 @@
3
3
  * Ai-panel.ts — AI assistant tab for the right panel (Stack B document assistant).
4
4
  *
5
5
  * Native lit-html chat UI (VSCode-Copilot style) over the reactive document-assistant
6
- * session: a view-state machine (key gate → sessions list ↔ chat), a message list with
6
+ * session: a view-state machine (sessions list ↔ chat), a message list with
7
7
  * stick-to-bottom scrolling, and the sticky composer.
8
8
  *
9
+ * Credentials are NOT a state of this panel. A provider key is a roaming APPLICATION setting
10
+ * configured once, so it lives in Preferences › Assistant (⌘,) — not in a dialog reachable only
11
+ * from the panel that is broken for want of one. The panel with no key configured still opens on an
12
+ * invitation to talk, with the way to fix it offered beneath. It repaints when a credential is
13
+ * saved or revoked by subscribing to `settings/preferences-accounts.ts`, which is a LEAF both
14
+ * modules depend on rather than an import back into the sheet.
15
+ *
9
16
  * Rendering: this panel owns a private rAF-coalesced render loop into the assistant
10
17
  * `.panel-body` container (bound once via {@link bindAiPanelHost}). It deliberately
11
18
  * bypasses the right-panel scheduler's focus guard — streaming must repaint while the
@@ -13,32 +20,39 @@
13
20
  * textarea is uncontrolled). The right panel renders the same template into the same
14
21
  * container on tab switches; lit reconciles both paths through one part cache.
15
22
  *
23
+ * @docs studio/ai/chat
16
24
  * @license MIT
17
25
  */
18
26
 
19
- import { html, render as litRender } from "lit-html";
27
+ import { html, render as litRender, nothing } from "lit-html";
20
28
  import type { TemplateResult } from "lit-html";
21
29
  import { effect, effectScope } from "../reactivity";
22
30
  import { createDocumentAssistant } from "../services/document-assistant";
31
+ import { writesForTurn } from "../services/ai-writes";
32
+ import { notify } from "../services/notify";
33
+ import { undo } from "../tabs/transact";
34
+ import { activeTab } from "../workspace/workspace";
23
35
  import { setOpenAiKey } from "../services/ai-settings";
24
36
  import { hasAiCredentials } from "../services/ai-models";
25
- import { createAiCredentialsForm } from "../ui/ai-credentials-form";
26
- import { createManagedConnect } from "../ui/ai-managed-connect";
37
+ import { openPreferences } from "../settings/preferences-dialog";
38
+ import { onCredentialsChanged } from "../settings/preferences-accounts";
39
+ import { setDockCollapsed } from "../shell";
40
+ import { hasSelection } from "../commands/context";
27
41
  import { clearMarkdownCache } from "./ai-chat/chat-markdown";
28
42
  import { renderChatHeader, renderMessageList } from "./ai-chat/chat-view";
29
43
  import { createComposer } from "./ai-chat/composer";
30
44
  import { renderSessionsList } from "./ai-chat/sessions-view";
45
+ import { setInspectorTab } from "./right-panel";
31
46
 
47
+ import type { AnyCommand } from "../commands/registry";
48
+ import type { CommandContext } from "../commands/context";
32
49
  import type { EffectScope } from "@vue/reactivity";
33
50
 
34
51
  // ─── State (module-level, persists across tab switches) ─────────────────────
35
52
 
36
53
  let mounted = false;
37
54
 
38
- /** Whether the OpenAI key form is showing (gate when no key, or re-edit via the gear). */
39
- let keyEditing = false;
40
-
41
- /** Which pane the panel shows once the key gate is passed. */
55
+ /** Which pane the panel shows. */
42
56
  let view: "chat" | "sessions" = "chat";
43
57
 
44
58
  /** Document AST assistant session — created lazily, persists across tab switches. */
@@ -107,6 +121,9 @@ export function mountAiPanel() {
107
121
  return;
108
122
  }
109
123
  mounted = true;
124
+ // A key saved (or revoked) in Preferences changes what this panel shows — the setup notice, and
125
+ // Whether the composer can send. One subscription, and no import back into the sheet.
126
+ onCredentialsChanged(scheduleAiRender);
110
127
  }
111
128
 
112
129
  // ─── Auto-scroll (stick to bottom unless the user scrolled up) ──────────────
@@ -133,38 +150,29 @@ function maintainScroll() {
133
150
  }
134
151
  }
135
152
 
136
- // ─── OpenAI key settings ─────────────────────────────────────────────────────
137
-
138
- /** The panel's shared credentials form (draft/model state lives inside the form's closure). */
139
- const credsForm = createAiCredentialsForm({
140
- onCancel: () => {
141
- keyEditing = false;
142
- },
143
- onSaved: () => {
144
- keyEditing = false;
145
- },
146
- requestRender: scheduleAiRender,
147
- });
148
-
149
- /** Open the key form, pre-filled with the current settings. */
150
- function startEditApiKey() {
151
- keyEditing = true;
152
- credsForm.startEdit();
153
- }
154
-
155
- // ─── Managed Cloudflare connect (Workers AI) ─────────────────────────────────
156
-
157
- /** Shared with the New Project modal's gates — see ui/ai-managed-connect.ts. */
158
- const managedConnect = createManagedConnect({ requestRender: scheduleAiRender });
153
+ // ─── The credentials gate's in-panel residue ─────────────────────────────────
159
154
 
160
155
  /**
161
- * The credentials gate: on managed platforms a keyless "Connect Cloudflare" (Workers AI) option
162
- * sits above the OpenAI-compatible key form — both are real, working paths.
156
+ * One line and the action that fixes it, under a chat that still invites a conversation.
157
+ *
158
+ * The action is `Preferences › Assistant`, not a dialog of this panel's own: a provider key is an
159
+ * application setting, and the surface that owns application settings is the one that can also list
160
+ * and revoke it. The probe fires here for the same reason the old gate fired it — a managed
161
+ * platform or an env-keyed dev server may already be configured, and only `/models` knows.
163
162
  */
164
- function renderKeyGate() {
163
+ function renderSetupNotice(): TemplateResult {
165
164
  return html`
166
- <div class="ai-tab-body">
167
- <div class="ai-status-center">${managedConnect.render()} ${credsForm.render()}</div>
165
+ <div class="ai-setup-notice">
166
+ <span>No AI provider is connected yet.</span>
167
+ <sp-button
168
+ size="s"
169
+ variant="secondary"
170
+ @click=${() => {
171
+ void openPreferences("assistant");
172
+ }}
173
+ >
174
+ Open Preferences…
175
+ </sp-button>
168
176
  </div>
169
177
  `;
170
178
  }
@@ -188,6 +196,64 @@ async function handleAssistantSend(text: string) {
188
196
  }
189
197
  }
190
198
 
199
+ /**
200
+ * Re-send the last user message — §7.4's Retry.
201
+ *
202
+ * `chatState.retryLast()` pops the failed assistant turn AND the user message that caused it, on
203
+ * the contract that the caller re-sends. It has been exported with zero callers since it was
204
+ * written, so a failed turn's only recovery was retyping the prompt. Read the text before popping;
205
+ * there is nowhere else it survives.
206
+ */
207
+ async function handleRetry(): Promise<void> {
208
+ const cs = assistant.chatState;
209
+ const lastUser = cs.messages.toReversed().find((m) => m.role === "user");
210
+ if (!lastUser) {
211
+ return;
212
+ }
213
+ const { content } = lastUser;
214
+ cs.retryLast();
215
+ scheduleAiRender();
216
+ await handleAssistantSend(content);
217
+ }
218
+
219
+ /**
220
+ * Undo everything one assistant turn changed — §7.4's "Restore to here".
221
+ *
222
+ * The loop opens one batch per turn per document, so undoing the turn is undoing that batch. The
223
+ * button is offered by the renderer only when every recorded change was transactional; this guard
224
+ * is the second half of the same promise, because a ledger can be trimmed (MAX_TURNS) between the
225
+ * render and the click and a Restore that silently restored SOME of a turn would be worse than one
226
+ * that refused.
227
+ *
228
+ * @param {string} messageId
229
+ */
230
+ /* Exported so the guard can be exercised directly: the button is not RENDERED for a turn that
231
+ touched disk, which would otherwise make the refusal path unreachable from the panel. */
232
+ export function handleRestore(messageId: string): void {
233
+ const writes = writesForTurn(messageId);
234
+ if (writes.length === 0) {
235
+ notify.warn("There is no longer a record of what that turn changed.", { source: "Assistant" });
236
+ return;
237
+ }
238
+ const disk = writes.filter((w) => w.disk).map((w) => w.path);
239
+ if (disk.length > 0) {
240
+ notify.warn(
241
+ `Cannot restore: ${disk.join(", ")} ${disk.length === 1 ? "was" : "were"} written straight ` +
242
+ "to disk, which undo cannot reach.",
243
+ { source: "Assistant" },
244
+ );
245
+ return;
246
+ }
247
+ const tab = activeTab.value;
248
+ if (!tab) {
249
+ notify.warn("Open the document that turn edited to restore it.", { source: "Assistant" });
250
+ return;
251
+ }
252
+ undo(tab);
253
+ notify.success("Restored to before that turn.", { action: "edit.redo", source: "Assistant" });
254
+ scheduleAiRender();
255
+ }
256
+
191
257
  /**
192
258
  * Seed the assistant with a prompt programmatically (e.g. the New Project flow handing off a
193
259
  * project brief). Delegates to the same send path as the composer. Safe to call right after the
@@ -225,7 +291,6 @@ let seededCount = 0;
225
291
  */
226
292
  export function seedAssistantMessages(messages: SeededAssistantMessage[]): void {
227
293
  setOpenAiKey("sk-demo");
228
- keyEditing = false;
229
294
  view = "chat";
230
295
  stickToBottom = true;
231
296
  for (const msg of messages) {
@@ -252,6 +317,35 @@ export function seedAssistantMessages(messages: SeededAssistantMessage[]): void
252
317
 
253
318
  // ─── Controls ─────────────────────────────────────────────────────────────────
254
319
 
320
+ /**
321
+ * Show the assistant: open the Inspector, then select its fourth tab.
322
+ *
323
+ * The two lines `view.setAssistant { open: true }` runs, in the module that owns the surface, so
324
+ * the three callers that need them — that record, `chat-panel.ts`'s pending-prompt handoff, and
325
+ * every `Assistant:` command below — do not each keep their own copy. `chat-panel.ts` had one
326
+ * inline, and a reveal that opens the dock but forgets the tab (or the reverse) is a silent
327
+ * half-success.
328
+ */
329
+ export function revealAssistant(): void {
330
+ setDockCollapsed("right", false);
331
+ setInspectorTab("assistant");
332
+ }
333
+
334
+ /**
335
+ * Whether a turn is in flight — the probe `commands/live-context.ts` declares as `aiStreaming` and
336
+ * projects onto `ctx.ai.streaming`.
337
+ *
338
+ * That source was declared optional with the note "there is nothing to read yet; the caller passes
339
+ * a probe when one exists", and no caller ever did — so `ctx.ai.streaming` read `false` forever and
340
+ * `assistant.stop` would have been permanently refused. Reading the reactive chat state here is
341
+ * what makes the fact LIVE: `createLiveContext` builds a fresh record per predicate evaluation, so
342
+ * a surface repainting from an effect tracks this status and re-renders when the stream starts or
343
+ * ends.
344
+ */
345
+ export function isAssistantStreaming(): boolean {
346
+ return assistant.chatState.status === "streaming";
347
+ }
348
+
255
349
  function stop() {
256
350
  assistant.stop();
257
351
  }
@@ -294,8 +388,10 @@ function activeSessionTitle(): string | null {
294
388
  // ─── Composer ───────────────────────────────────────────────────────────────
295
389
 
296
390
  const composer = createComposer({
297
- isStreaming: () => assistant.chatState.status === "streaming",
298
- onOpenSettings: startEditApiKey,
391
+ isStreaming: isAssistantStreaming,
392
+ onOpenSettings: () => {
393
+ void openPreferences("assistant");
394
+ },
299
395
  onSend: (text) => {
300
396
  void handleAssistantSend(text);
301
397
  },
@@ -303,26 +399,155 @@ const composer = createComposer({
303
399
  requestRender: scheduleAiRender,
304
400
  });
305
401
 
402
+ /**
403
+ * Reveal the assistant, put it on the chat view, and place the caret in the composer.
404
+ *
405
+ * The focus rides a frame because {@link scheduleAiRender} is rAF-coalesced: revealing from the
406
+ * sessions list means the textarea does not exist yet, and focusing a node that is about to be
407
+ * replaced would leave the caret nowhere. Ordering holds because this frame is queued after the
408
+ * render's.
409
+ */
410
+ function focusComposer(): void {
411
+ revealAssistant();
412
+ if (view !== "chat") {
413
+ view = "chat";
414
+ scheduleAiRender();
415
+ }
416
+ requestAnimationFrame(() => {
417
+ composer.focus();
418
+ });
419
+ }
420
+
421
+ // ─── The `Assistant:` command family (§11.1) ────────────────────────────────
422
+
423
+ /**
424
+ * Six records, beside the chat session they write.
425
+ *
426
+ * §11.1 pays for the chat column's demotion into an Inspector tab with a command family, and the
427
+ * `Assistant` category — declared in `commands/levels.ts` since the taxonomy landed — held ZERO
428
+ * records. Every capability below already existed and every one of them existed ONLY as a button in
429
+ * this panel: not in the palette, not bindable, not reachable by `__jxAutomation` or by name, and
430
+ * absent from the generated commands and shortcuts sheets. A capability that one surface can reach
431
+ * and the registry cannot is the second definition site inverted.
432
+ *
433
+ * **All six are `level: "application"`, by principle 3 — a record is filed by the level of the
434
+ * state it WRITES, not the state it reads.** The chat session is application state: it outlives the
435
+ * open document, survives project close, and `assistant.attachSelection` is the case that proves
436
+ * the rule — it READS the canvas selection and writes a chip into the composer, so it is
437
+ * application, not selection, however selection-ish it looks. That is also why it may declare
438
+ * `menus: ["palette"]` at all: `blockbar` and `context/element` admit selection-level records
439
+ * only.
440
+ *
441
+ * **No `aiTool` on any of them.** The assistant projecting "start a new chat" into its own tool
442
+ * list would let a turn end its own conversation; the tier tables in `services/ai-tools.ts` gate
443
+ * what the agent may do TO A PROJECT, not to the chat it is running inside.
444
+ */
445
+ export function assistantCommands(): AnyCommand[] {
446
+ return [
447
+ {
448
+ category: "Assistant",
449
+ id: "assistant.focus",
450
+ level: "application",
451
+ /* A sixth record, and it earns its place: `inspector.focus.assistant` (⌘⇧4) is DOCUMENT-level
452
+ and refuses when nothing is open — which is exactly the state the assistant is most wanted
453
+ in, because the panel deliberately renders with no project and no document. `view.setAssistant`
454
+ is `menus: ["never"]`. Neither puts the caret anywhere, so neither answers "let me type".
455
+ The title is distinct on purpose: two palette rows printing one sentence is the defect
456
+ `tests/app-commands-composition.test.ts` refuses, and "Show Assistant" is already taken. */
457
+ title: "Focus Composer",
458
+ keybinding: "mod+shift+a",
459
+ menus: ["palette"],
460
+ group: "1_chat",
461
+ run: focusComposer,
462
+ },
463
+ {
464
+ category: "Assistant",
465
+ id: "assistant.newChat",
466
+ level: "application",
467
+ title: "New Chat",
468
+ menus: ["palette"],
469
+ group: "1_chat",
470
+ // No `enablement` on the stream: `newChat()` calls `stop()` first (see
471
+ // `services/document-assistant.ts`), so starting one mid-turn is already the handled case.
472
+ run: () => {
473
+ revealAssistant();
474
+ newChat();
475
+ },
476
+ },
477
+ {
478
+ category: "Assistant",
479
+ id: "assistant.history",
480
+ level: "application",
481
+ title: "Chat History",
482
+ menus: ["palette"],
483
+ group: "1_chat",
484
+ run: () => {
485
+ revealAssistant();
486
+ showSessions();
487
+ },
488
+ },
489
+ {
490
+ category: "Assistant",
491
+ id: "assistant.attachSelection",
492
+ level: "application",
493
+ title: "Attach Selection",
494
+ menus: ["palette"],
495
+ group: "2_turn",
496
+ requires: "an element selected on the canvas",
497
+ // `hasSelection` is `commands/context.ts`'s shared predicate — the same one the element menu
498
+ // And the structural verbs are gated on, so "a selection" means one thing in three menus.
499
+ when: (ctx: CommandContext) => hasSelection(ctx),
500
+ run: () => {
501
+ if (!composer.attachSelection()) {
502
+ // Reachable despite `when`: a script or the palette can race the selection away between
503
+ // The predicate and the run, and a silent no-op would look like the chip had landed.
504
+ notify.warn("Nothing is selected to attach.", { source: "Assistant" });
505
+ return;
506
+ }
507
+ focusComposer();
508
+ },
509
+ },
510
+ {
511
+ category: "Assistant",
512
+ id: "assistant.retry",
513
+ level: "application",
514
+ title: "Retry Last Message",
515
+ menus: ["palette"],
516
+ group: "2_turn",
517
+ requires: "a connected AI provider, and no turn already in flight",
518
+ /* `ctx.ai.configured` and `ctx.ai.streaming` have been declared in `commands/context.ts` with
519
+ zero readers; this record and `assistant.stop` are the first. Re-sending with no provider
520
+ connected reproduces the same failure the error row is already explaining, and re-sending
521
+ mid-stream would interleave two turns. */
522
+ enablement: (ctx: CommandContext) => ctx.ai.configured && !ctx.ai.streaming,
523
+ run: () => {
524
+ revealAssistant();
525
+ void handleRetry();
526
+ },
527
+ },
528
+ {
529
+ category: "Assistant",
530
+ id: "assistant.stop",
531
+ level: "application",
532
+ title: "Stop Responding",
533
+ menus: ["palette"],
534
+ group: "2_turn",
535
+ requires: "a turn in flight",
536
+ enablement: (ctx: CommandContext) => ctx.ai.streaming,
537
+ run: stop,
538
+ },
539
+ ];
540
+ }
541
+
306
542
  // ─── Template ───────────────────────────────────────────────────────────────
307
543
 
308
544
  /** @returns {TemplateResult} */
309
545
  export function renderAiPanelTemplate(): TemplateResult {
310
- /* The document assistant authenticates via the AI proxy. Gate the chat
311
- behind the key form until a key is stored locally OR the proxy reports
312
- itself configured (managed platforms, env-keyed dev servers). */
313
- if (!hasAiCredentials() || keyEditing) {
314
- if (!keyEditing) {
315
- managedConnect.ensureProbe();
316
- }
317
- return renderKeyGate();
318
- }
319
-
320
546
  if (view === "sessions") {
321
547
  return html`
322
548
  <div class="ai-tab-body">
323
549
  ${renderSessionsList({
324
550
  onDelete: deleteSession,
325
- onNew: newChat,
326
551
  onOpen: openSession,
327
552
  sessions: assistant.listSessions(),
328
553
  })}
@@ -334,19 +559,20 @@ export function renderAiPanelTemplate(): TemplateResult {
334
559
  return html`
335
560
  <div class="ai-tab-body">
336
561
  ${renderChatHeader({
337
- onNewChat: newChat,
338
- onShowSessions: showSessions,
562
+ overBudget: cs.contextWarning,
339
563
  streaming: cs.status === "streaming",
340
564
  title: activeSessionTitle(),
565
+ tokens: cs.tokenCount,
341
566
  })}
342
567
  ${renderMessageList({
343
568
  error: cs.error,
344
569
  listRef: onMessagesListRef,
345
570
  messages: cs.messages,
571
+ onRestore: handleRestore,
346
572
  onScroll: onMessagesScroll,
347
573
  status: cs.status,
348
574
  })}
349
- ${composer.render()}
575
+ ${hasAiCredentials() ? nothing : renderSetupNotice()} ${composer.render()}
350
576
  </div>
351
577
  `;
352
578
  }