@jxsuite/studio 4.1.0 → 5.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 (612) hide show
  1. package/README.md +1 -1
  2. package/data/elements-meta.json +5 -15
  3. package/data/html-meta.json +51 -6
  4. package/dist/chunks/{2020-n6tfwnda.js → 2020-g79n01v9.js} +14 -14
  5. package/dist/chunks/action-group-sp6tna8v.js +118 -0
  6. package/dist/chunks/adapter-nj7tnjfn.js +13 -0
  7. package/dist/chunks/cf-account-picker-qwkm9zrf.js +495 -0
  8. package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
  9. package/dist/chunks/color-area-v17df7b8.js +154 -0
  10. package/dist/chunks/color-field-anwybnkn.js +208 -0
  11. package/dist/chunks/color-slider-44ez96fc.js +79 -0
  12. package/dist/chunks/color-xgg3kfw7.js +35 -0
  13. package/dist/chunks/combobox-5e7jev23.js +236 -0
  14. package/dist/chunks/components-vj72gqtq.js +20 -0
  15. package/dist/chunks/content-source-5mex4x1h.js +46 -0
  16. package/dist/chunks/convert-to-repeater-n64h8znc.js +639 -0
  17. package/dist/chunks/dialog-s890b918.js +85 -0
  18. package/dist/chunks/editor-3qhbg51x.js +35 -0
  19. package/dist/chunks/entry-commands-234hjnqw.js +42 -0
  20. package/dist/chunks/extension-sections-3hpcambp.js +651 -0
  21. package/dist/chunks/file-ops-8yhd83xr.js +47 -0
  22. package/dist/chunks/files-hnxqxtsg.js +72 -0
  23. package/dist/chunks/format-host-779sfp2n.js +40 -0
  24. package/dist/chunks/fs-events-b88z7g4h.js +18 -0
  25. package/dist/chunks/git-panel-xwj8fpab.js +49 -0
  26. package/dist/chunks/icons-yy10wk9r.js +402 -0
  27. package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
  28. package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
  29. package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
  30. package/dist/chunks/iframe-host-syr0f9sb.js +115 -0
  31. package/dist/chunks/{index-wcnt3r9g.js → index-mdmyx6s2.js} +11 -11
  32. package/dist/chunks/index-n4j7qxyr.js +109 -0
  33. package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
  34. package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
  35. package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
  36. package/dist/chunks/layers-ff81wthn.js +30 -0
  37. package/dist/chunks/layers-panel-pnnghw12.js +40 -0
  38. package/dist/chunks/listbox-6v2ac08j.js +44 -0
  39. package/dist/chunks/lit-html-m244w9nh.js +17 -0
  40. package/dist/chunks/media-picker-cqhhxhhe.js +33 -0
  41. package/dist/chunks/menu-9p2w46gj.js +15 -0
  42. package/dist/chunks/menu-q99sy9rf.js +285 -0
  43. package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
  44. package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
  45. package/dist/chunks/{monaco-setup-vx9bhp1d.js → monaco-setup-8r62fj6y.js} +27 -37
  46. package/dist/chunks/notify-628t0anh.js +21 -0
  47. package/dist/chunks/number-field-5cndyft8.js +72 -0
  48. package/dist/chunks/parse-0zx14y15.js +10 -0
  49. package/dist/chunks/platform-ts9cg1a4.js +15 -0
  50. package/dist/chunks/popover-47z3ytva.js +25 -0
  51. package/dist/chunks/publish-panel-5zt840sy.js +27 -0
  52. package/dist/chunks/quick-search-3748564r.js +45 -0
  53. package/dist/chunks/references-qvvxej7h.js +26 -0
  54. package/dist/chunks/right-panel-eccz92qt.js +45 -0
  55. package/dist/chunks/section-registry-5pq32t0q.js +25 -0
  56. package/dist/chunks/select-2r16ez41.js +49 -0
  57. package/dist/chunks/split-g7nm1rgb.js +191 -0
  58. package/dist/chunks/studio-0hqbpbd0.js +62 -0
  59. package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
  60. package/dist/chunks/{studio-b55y6ewx.js → studio-1knfqgy7.js} +58 -58
  61. package/dist/chunks/{studio-2b946z26.js → studio-1z1kcjv4.js} +3628 -6095
  62. package/dist/chunks/studio-3773086z.js +111 -0
  63. package/dist/chunks/{studio-4r1pv6zf.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/{studio-x813zp48.js → studio-3rz5md06.js} +30 -30
  65. package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
  66. package/dist/chunks/studio-5te5tqng.js +81 -0
  67. package/dist/chunks/studio-5wt9nvhd.js +4763 -0
  68. package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
  69. package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
  70. package/dist/chunks/studio-6xa21ej9.js +28 -0
  71. package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
  72. package/dist/chunks/{studio-gcye7qka.js → studio-7e11jpa9.js} +21 -21
  73. package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
  74. package/dist/chunks/studio-7xnmgv66.js +13615 -0
  75. package/dist/chunks/studio-8scdew0e.js +258 -0
  76. package/dist/chunks/{studio-fbf92ckf.js → studio-93zafjcm.js} +275 -163
  77. package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
  78. package/dist/chunks/studio-a79k90n9.js +1162 -0
  79. package/dist/chunks/studio-aj37eer3.js +422 -0
  80. package/dist/chunks/studio-b0k5tqgp.js +2432 -0
  81. package/dist/chunks/studio-b4s9eykd.js +2811 -0
  82. package/dist/chunks/{studio-f3wqjtk5.js → studio-d0300636.js} +5076 -18
  83. package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
  84. package/dist/chunks/studio-e1pgga3k.js +839 -0
  85. package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
  86. package/dist/chunks/{studio-q43a5y9h.js → studio-g3jevyjt.js} +16 -16
  87. package/dist/chunks/studio-gb13095a.js +2806 -0
  88. package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
  89. package/dist/chunks/{studio-dm19q43r.js → studio-hhvs4sdg.js} +10 -10
  90. package/dist/chunks/{studio-x4qkdat5.js → studio-js8nv53n.js} +1749 -2481
  91. package/dist/chunks/{studio-qjy2z9bv.js → studio-jxp12rnj.js} +32 -137
  92. package/dist/chunks/{studio-trxrabqf.js → studio-k75n7vhp.js} +527 -283
  93. package/dist/chunks/{studio-q9jd1a60.js → studio-kcgff4r0.js} +15 -18
  94. package/dist/chunks/studio-kkqkcp3d.js +17668 -0
  95. package/dist/chunks/studio-mhhyamxf.js +763 -0
  96. package/dist/chunks/{studio-cft9r4r7.js → studio-nq5yf5mp.js} +22 -22
  97. package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
  98. package/dist/chunks/studio-nzzpvzx9.js +185 -0
  99. package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
  100. package/dist/chunks/{studio-3bqpr0zh.js → studio-pxbgypmg.js} +299 -110
  101. package/dist/chunks/studio-q0a3yk4n.js +33 -0
  102. package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
  103. package/dist/chunks/{studio-6yw4y3my.js → studio-qhhm6hbt.js} +8 -8
  104. package/dist/chunks/studio-qk4bfsq2.js +362 -0
  105. package/dist/chunks/{studio-msd847zn.js → studio-qk90fgqm.js} +361 -90
  106. package/dist/chunks/{studio-jkftxyvz.js → studio-r6nvacqs.js} +5861 -2154
  107. package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
  108. package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
  109. package/dist/chunks/studio-rs76k67r.js +12 -0
  110. package/dist/chunks/studio-sbjyc8bt.js +954 -0
  111. package/dist/chunks/{studio-1wagb550.js → studio-syg2tadj.js} +11 -11
  112. package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
  113. package/dist/chunks/studio-tqgryxwg.js +1171 -0
  114. package/dist/chunks/studio-try13h8c.js +8448 -0
  115. package/dist/chunks/studio-vfq8qpjt.js +1219 -0
  116. package/dist/chunks/studio-vhv5tgxm.js +51 -0
  117. package/dist/chunks/{studio-ahn3pdgx.js → studio-vw7mzp6z.js} +52 -38
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/studio-wqz6dggm.js +1356 -0
  120. package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
  121. package/dist/chunks/studio-yxa81f45.js +12 -0
  122. package/dist/chunks/studio-zdn2g6dt.js +148 -0
  123. package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
  124. package/dist/chunks/tabs-wbp1cdws.js +156 -0
  125. package/dist/chunks/textfield-abk6qyee.js +73 -0
  126. package/dist/chunks/toast-780pvfbv.js +27 -0
  127. package/dist/chunks/toast-host-3sqv46sn.js +116 -0
  128. package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
  129. package/dist/chunks/tooltip-eptb614w.js +369 -0
  130. package/dist/chunks/tree-a73p0pqm.js +367 -0
  131. package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
  132. package/dist/chunks/workspace-t55jdjbx.js +69 -0
  133. package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
  134. package/dist/iframe-entry.js +1873 -673
  135. package/dist/studio.js +52757 -36535
  136. package/dist/workers/editor.worker.js +1040 -1085
  137. package/dist/workers/json.worker.js +1946 -1991
  138. package/dist/workers/ts.worker.js +4960 -5005
  139. package/index.html +1 -0
  140. package/package.json +18 -52
  141. package/src/about/about-modal.ts +72 -123
  142. package/src/browse/library-commands.ts +20 -49
  143. package/src/browse/library-layouts.ts +87 -218
  144. package/src/browse/library-pane.ts +406 -438
  145. package/src/canvas/canvas-helpers.ts +0 -49
  146. package/src/canvas/canvas-live-render.ts +25 -2
  147. package/src/canvas/canvas-render.ts +666 -231
  148. package/src/canvas/canvas-surface.ts +0 -1
  149. package/src/canvas/canvas-utils.ts +333 -113
  150. package/src/canvas/dialog-path.ts +76 -0
  151. package/src/canvas/dialog-state.ts +67 -0
  152. package/src/canvas/diff-marks.ts +252 -0
  153. package/src/canvas/diff-toolbar.ts +349 -0
  154. package/src/canvas/diff-view.ts +123 -0
  155. package/src/canvas/edit-width-drag.ts +187 -0
  156. package/src/canvas/edit-width.ts +150 -0
  157. package/src/canvas/iframe-entry.ts +125 -8
  158. package/src/canvas/iframe-host.ts +271 -15
  159. package/src/canvas/iframe-interaction.ts +133 -13
  160. package/src/canvas/iframe-patch.ts +7 -1
  161. package/src/canvas/iframe-position.ts +5 -6
  162. package/src/canvas/iframe-protocol.ts +106 -5
  163. package/src/canvas/iframe-render.ts +373 -5
  164. package/src/canvas/iframe-slash.ts +2 -2
  165. package/src/canvas/iframe-subtree.ts +5 -8
  166. package/src/canvas/path-mapping.ts +25 -3
  167. package/src/canvas/popover-path.ts +106 -0
  168. package/src/canvas/popover-state.ts +155 -0
  169. package/src/canvas/surface-registry.ts +21 -10
  170. package/src/collab/presence-chips.ts +51 -73
  171. package/src/commands/app-commands.ts +10 -0
  172. package/src/commands/budget.ts +12 -0
  173. package/src/commands/command-args.ts +404 -6
  174. package/src/commands/defaults.ts +44 -14
  175. package/src/commands/live-context.ts +11 -5
  176. package/src/commands/reference.ts +12 -2
  177. package/src/commands/registry.ts +177 -10
  178. package/src/commands/run-reported.ts +120 -0
  179. package/src/content/entry-commands.ts +16 -23
  180. package/src/content/entry-editor.ts +144 -101
  181. package/src/editor/canvas-slash-bridge.ts +2 -2
  182. package/src/editor/context-menu.ts +49 -200
  183. package/src/editor/convert-to-component.ts +42 -82
  184. package/src/editor/convert-to-repeater.ts +132 -173
  185. package/src/editor/inline-edit.ts +11 -0
  186. package/src/editor/shortcuts.ts +76 -49
  187. package/src/editor/slash-menu.ts +150 -157
  188. package/src/files/components.ts +39 -0
  189. package/src/files/file-ops.ts +117 -11
  190. package/src/files/files.ts +944 -660
  191. package/src/files/json-layout.ts +474 -0
  192. package/src/files/serialize-document.ts +8 -1
  193. package/src/format/convert-file.ts +16 -10
  194. package/src/format/format-host.ts +50 -1
  195. package/src/github/github-auth.ts +71 -29
  196. package/src/github/github-publish.ts +57 -65
  197. package/src/grid/cell-editors.ts +46 -4
  198. package/src/grid/cell-popovers.ts +65 -62
  199. package/src/grid/grid-open.ts +86 -64
  200. package/src/grid/grid-panel.ts +390 -469
  201. package/src/grid/redirects-grid.ts +40 -44
  202. package/src/hosting/layout.ts +2 -0
  203. package/src/i18n/i18n-commands.ts +137 -62
  204. package/src/media/media-pane.ts +83 -133
  205. package/src/new-project/add-repo-modal.ts +125 -176
  206. package/src/new-project/import-tab.ts +181 -252
  207. package/src/new-project/location-fields.ts +93 -160
  208. package/src/new-project/new-project-modal.ts +376 -367
  209. package/src/packages/jxsuite-update.ts +76 -18
  210. package/src/packages/pull-package-sync.ts +5 -1
  211. package/src/panels/activity-panel.ts +137 -104
  212. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  213. package/src/panels/ai-chat/chat-view.ts +307 -472
  214. package/src/panels/ai-chat/composer.ts +175 -163
  215. package/src/panels/ai-chat/sessions-view.ts +31 -62
  216. package/src/panels/ai-panel.ts +213 -185
  217. package/src/panels/block-action-bar.ts +444 -645
  218. package/src/panels/bottom-dock.ts +112 -47
  219. package/src/panels/chat-panel.ts +19 -14
  220. package/src/panels/data-explorer.ts +141 -102
  221. package/src/panels/data-grid.ts +183 -150
  222. package/src/panels/dnd.ts +75 -20
  223. package/src/panels/editors.ts +26 -19
  224. package/src/panels/elements-panel.ts +243 -186
  225. package/src/panels/empty-state.ts +26 -42
  226. package/src/panels/events-panel.ts +950 -729
  227. package/src/panels/formula-workspace.ts +434 -207
  228. package/src/panels/frontmatter-fields.ts +185 -153
  229. package/src/panels/frontmatter-panel.ts +411 -187
  230. package/src/panels/git-diff-open.ts +148 -0
  231. package/src/panels/git-panel.ts +679 -605
  232. package/src/panels/head-panel.ts +617 -435
  233. package/src/panels/i18n-panel.ts +148 -135
  234. package/src/panels/imports-panel.ts +388 -414
  235. package/src/panels/jump-bar.ts +175 -147
  236. package/src/panels/layers-panel.ts +785 -671
  237. package/src/panels/left-panel.ts +166 -94
  238. package/src/panels/navigator-panels.ts +1 -1
  239. package/src/panels/pane-context.ts +529 -677
  240. package/src/panels/pane-grid.ts +265 -241
  241. package/src/panels/panel-registry.ts +15 -4
  242. package/src/panels/problems-panel.ts +181 -99
  243. package/src/panels/properties-panel.ts +1525 -966
  244. package/src/panels/provenance.ts +31 -113
  245. package/src/panels/quick-search.ts +223 -184
  246. package/src/panels/right-panel.ts +135 -169
  247. package/src/panels/seo-modal.ts +346 -167
  248. package/src/panels/settings-menu.ts +114 -661
  249. package/src/panels/settings-pane.ts +102 -86
  250. package/src/panels/signals-panel.ts +1318 -1172
  251. package/src/panels/statement-editor.ts +556 -428
  252. package/src/panels/style-panel.ts +1367 -630
  253. package/src/panels/style-utils.ts +36 -32
  254. package/src/panels/stylebook-doc.ts +30 -73
  255. package/src/panels/stylebook-layers-panel.ts +202 -109
  256. package/src/panels/stylebook-panel.ts +124 -88
  257. package/src/panels/tab-strip.ts +386 -288
  258. package/src/platforms/cloud.ts +106 -16
  259. package/src/platforms/devserver.ts +13 -0
  260. package/src/publish/deploy-checklist.ts +124 -78
  261. package/src/publish/publish-commands.ts +4 -12
  262. package/src/publish/publish-panel.ts +134 -328
  263. package/src/services/a11y-report.ts +100 -43
  264. package/src/services/ai-command-tools.ts +538 -0
  265. package/src/services/ai-project-tools.ts +8 -2
  266. package/src/services/ai-session-store.ts +6 -0
  267. package/src/services/ai-system-prompt.ts +112 -24
  268. package/src/services/ai-tools.ts +36 -212
  269. package/src/services/ai-write-report.ts +174 -0
  270. package/src/services/document-assistant.ts +59 -8
  271. package/src/services/idle.ts +16 -14
  272. package/src/services/live-surfaces.ts +237 -0
  273. package/src/services/model-uri.ts +75 -0
  274. package/src/services/notify.ts +63 -6
  275. package/src/services/popover-report.ts +325 -0
  276. package/src/services/surface-registry.ts +56 -0
  277. package/src/services/tool-executor.ts +6 -0
  278. package/src/settings/contexts-section.ts +301 -299
  279. package/src/settings/contributed-section.ts +361 -222
  280. package/src/settings/css-vars-editor.ts +320 -325
  281. package/src/settings/defs-editor.ts +572 -535
  282. package/src/settings/dependencies-editor.ts +79 -107
  283. package/src/settings/extension-commands.ts +379 -0
  284. package/src/settings/extension-rows.ts +113 -0
  285. package/src/settings/extensions-section.ts +287 -0
  286. package/src/settings/general-settings.ts +130 -181
  287. package/src/settings/head-editor.ts +10 -305
  288. package/src/settings/locales-section.ts +146 -196
  289. package/src/settings/preferences-accounts.ts +1 -1
  290. package/src/settings/preferences-dialog.ts +350 -330
  291. package/src/settings/project-sections.ts +108 -181
  292. package/src/settings/schema-field-ui.ts +11 -399
  293. package/src/settings/section-registry.ts +8 -1
  294. package/src/settings/settings-document.ts +31 -29
  295. package/src/shell/tree.ts +42 -87
  296. package/src/shell.ts +48 -36
  297. package/src/studio.ts +104 -69
  298. package/src/style/token-ref.ts +0 -39
  299. package/src/surfaces/about.json +263 -0
  300. package/src/surfaces/about.ts +163 -0
  301. package/src/surfaces/add-repo.json +486 -0
  302. package/src/surfaces/add-repo.ts +236 -0
  303. package/src/surfaces/ai-chat.json +2185 -0
  304. package/src/surfaces/ai-chat.ts +549 -0
  305. package/src/surfaces/ai-credentials-form.json +332 -0
  306. package/src/surfaces/ai-credentials-form.ts +151 -0
  307. package/src/surfaces/ai-managed-connect.json +108 -0
  308. package/src/surfaces/ai-managed-connect.ts +123 -0
  309. package/src/surfaces/ai-model-picker.json +114 -0
  310. package/src/surfaces/ai-model-picker.ts +139 -0
  311. package/src/surfaces/block-action-bar.json +640 -0
  312. package/src/surfaces/block-action-bar.ts +368 -0
  313. package/src/surfaces/bottom-dock.json +154 -0
  314. package/src/surfaces/bottom-dock.ts +125 -0
  315. package/src/surfaces/canvas-stage.json +444 -0
  316. package/src/surfaces/canvas-stage.ts +253 -0
  317. package/src/surfaces/cf-account-picker.json +300 -0
  318. package/src/surfaces/cf-account-picker.ts +214 -0
  319. package/src/surfaces/commandbar.json +985 -0
  320. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +417 -391
  321. package/src/surfaces/convert-repeater.json +309 -0
  322. package/src/surfaces/convert-repeater.ts +276 -0
  323. package/src/surfaces/data-actions.json +157 -0
  324. package/src/surfaces/data-actions.ts +115 -0
  325. package/src/surfaces/dialog.json +289 -0
  326. package/src/surfaces/dialog.ts +343 -0
  327. package/src/surfaces/diff-toolbar.json +266 -0
  328. package/src/surfaces/diff-toolbar.ts +139 -0
  329. package/src/surfaces/doc-header.json +739 -0
  330. package/src/surfaces/doc-header.ts +223 -0
  331. package/src/surfaces/empty-state.json +152 -0
  332. package/src/surfaces/empty-state.ts +173 -0
  333. package/src/surfaces/entry-editor.json +281 -0
  334. package/src/surfaces/entry-editor.ts +191 -0
  335. package/src/surfaces/expression-editor.json +977 -0
  336. package/src/surfaces/expression-editor.ts +266 -0
  337. package/src/surfaces/files-panel.json +592 -0
  338. package/src/surfaces/files-panel.ts +301 -0
  339. package/src/surfaces/formula-palette.json +364 -0
  340. package/src/surfaces/formula-palette.ts +340 -0
  341. package/src/surfaces/git-panel.json +1822 -0
  342. package/src/surfaces/git-panel.ts +272 -0
  343. package/src/surfaces/github-auth.json +112 -0
  344. package/src/surfaces/github-auth.ts +139 -0
  345. package/src/surfaces/github-publish.json +206 -0
  346. package/src/surfaces/github-publish.ts +169 -0
  347. package/src/surfaces/grid-cell.json +218 -0
  348. package/src/surfaces/grid-cell.ts +120 -0
  349. package/src/surfaces/grid-open.json +147 -0
  350. package/src/surfaces/grid-open.ts +87 -0
  351. package/src/surfaces/grid-panel.json +706 -0
  352. package/src/surfaces/grid-panel.ts +206 -0
  353. package/src/surfaces/grid-replace.json +179 -0
  354. package/src/surfaces/grid-replace.ts +89 -0
  355. package/src/surfaces/grid-views.json +446 -0
  356. package/src/surfaces/grid-views.ts +172 -0
  357. package/src/surfaces/inspector-dock.json +187 -0
  358. package/src/surfaces/inspector-dock.ts +161 -0
  359. package/src/surfaces/jump-bar.json +243 -0
  360. package/src/surfaces/jump-bar.ts +129 -0
  361. package/src/surfaces/jxsuite-update.json +146 -0
  362. package/src/surfaces/jxsuite-update.ts +149 -0
  363. package/src/surfaces/library-pane.json +1509 -0
  364. package/src/surfaces/library-pane.ts +363 -0
  365. package/src/surfaces/logic-panel.json +1949 -0
  366. package/src/surfaces/logic-panel.ts +369 -0
  367. package/src/surfaces/logic-workspace.json +685 -0
  368. package/src/surfaces/logic-workspace.ts +238 -0
  369. package/src/surfaces/media-browser.json +303 -0
  370. package/src/surfaces/media-browser.ts +145 -0
  371. package/src/surfaces/media-field.json +163 -0
  372. package/src/surfaces/media-field.ts +116 -0
  373. package/src/surfaces/media-pane.json +513 -0
  374. package/src/surfaces/media-pane.ts +197 -0
  375. package/src/surfaces/menu.json +232 -0
  376. package/src/surfaces/menu.ts +375 -0
  377. package/src/surfaces/navigator-dock.json +113 -0
  378. package/src/surfaces/navigator-dock.ts +130 -0
  379. package/src/surfaces/new-project.json +1654 -0
  380. package/src/surfaces/new-project.ts +411 -0
  381. package/src/surfaces/palette.json +535 -0
  382. package/src/surfaces/pane-context.json +1497 -0
  383. package/src/surfaces/pane-context.ts +513 -0
  384. package/src/surfaces/pane-grid.json +188 -0
  385. package/src/surfaces/pane-grid.ts +250 -0
  386. package/src/surfaces/panel-activity.json +563 -0
  387. package/src/surfaces/panel-activity.ts +187 -0
  388. package/src/surfaces/panel-data.json +141 -0
  389. package/src/surfaces/panel-data.ts +156 -0
  390. package/src/surfaces/panel-deploy-checklist.json +283 -0
  391. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  392. package/src/surfaces/panel-elements.json +367 -0
  393. package/src/surfaces/panel-elements.ts +175 -0
  394. package/src/surfaces/panel-i18n.json +569 -0
  395. package/src/surfaces/panel-i18n.ts +212 -0
  396. package/src/surfaces/panel-imports.json +780 -0
  397. package/src/surfaces/panel-imports.ts +209 -0
  398. package/src/surfaces/panel-outline.json +734 -0
  399. package/src/surfaces/panel-outline.ts +326 -0
  400. package/src/surfaces/panel-page.json +1017 -0
  401. package/src/surfaces/panel-page.ts +240 -0
  402. package/src/surfaces/panel-problems.json +497 -0
  403. package/src/surfaces/panel-problems.ts +157 -0
  404. package/src/surfaces/panel-signals.json +1973 -0
  405. package/src/surfaces/panel-signals.ts +436 -0
  406. package/src/surfaces/panel-stylebook-layers.json +317 -0
  407. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  408. package/src/surfaces/preferences.json +850 -0
  409. package/src/surfaces/preferences.ts +332 -0
  410. package/src/surfaces/progress-modal.json +110 -0
  411. package/src/surfaces/progress-modal.ts +150 -0
  412. package/src/surfaces/properties-panel.json +1578 -0
  413. package/src/surfaces/properties-panel.ts +337 -0
  414. package/src/surfaces/publish.json +945 -0
  415. package/src/surfaces/publish.ts +392 -0
  416. package/src/surfaces/push-plan.json +110 -0
  417. package/src/surfaces/push-plan.ts +87 -0
  418. package/src/surfaces/rail.json +255 -0
  419. package/src/surfaces/rail.ts +206 -0
  420. package/src/surfaces/reference-field.json +191 -0
  421. package/src/surfaces/reference-field.ts +168 -0
  422. package/src/surfaces/schema-builder.json +1011 -0
  423. package/src/surfaces/schema-builder.ts +181 -0
  424. package/src/surfaces/schema-form.json +1013 -0
  425. package/src/surfaces/schema-form.ts +287 -0
  426. package/src/surfaces/secret-field.json +60 -0
  427. package/src/surfaces/secret-field.ts +146 -0
  428. package/src/surfaces/seo.json +932 -0
  429. package/src/surfaces/seo.ts +334 -0
  430. package/src/surfaces/settings-contexts.json +538 -0
  431. package/src/surfaces/settings-contexts.ts +196 -0
  432. package/src/surfaces/settings-contributed.json +489 -0
  433. package/src/surfaces/settings-contributed.ts +199 -0
  434. package/src/surfaces/settings-css-vars.json +820 -0
  435. package/src/surfaces/settings-css-vars.ts +199 -0
  436. package/src/surfaces/settings-defs.json +1363 -0
  437. package/src/surfaces/settings-defs.ts +232 -0
  438. package/src/surfaces/settings-deploy.json +108 -0
  439. package/src/surfaces/settings-deploy.ts +135 -0
  440. package/src/surfaces/settings-extensions.json +486 -0
  441. package/src/surfaces/settings-extensions.ts +201 -0
  442. package/src/surfaces/settings-head.json +779 -0
  443. package/src/surfaces/settings-head.ts +397 -0
  444. package/src/surfaces/settings-locales.json +420 -0
  445. package/src/surfaces/settings-locales.ts +137 -0
  446. package/src/surfaces/settings-overview.json +423 -0
  447. package/src/surfaces/settings-overview.ts +218 -0
  448. package/src/surfaces/settings-packages.json +549 -0
  449. package/src/surfaces/settings-packages.ts +158 -0
  450. package/src/surfaces/settings-pane.json +147 -0
  451. package/src/surfaces/settings-pane.ts +150 -0
  452. package/src/surfaces/settings-rawjson.json +104 -0
  453. package/src/surfaces/settings-rawjson.ts +107 -0
  454. package/src/surfaces/shell.json +99 -0
  455. package/src/surfaces/shell.ts +30 -0
  456. package/src/surfaces/slash-menu.json +180 -0
  457. package/src/surfaces/slash-menu.ts +272 -0
  458. package/src/surfaces/statements.json +607 -0
  459. package/src/surfaces/statements.ts +238 -0
  460. package/src/surfaces/statusbar.json +94 -0
  461. package/src/{panels → surfaces}/statusbar.ts +164 -90
  462. package/src/surfaces/style-panel.json +1643 -0
  463. package/src/surfaces/style-panel.ts +338 -0
  464. package/src/surfaces/stylebook-chrome.json +122 -0
  465. package/src/surfaces/stylebook-chrome.ts +122 -0
  466. package/src/surfaces/tab-strip.json +448 -0
  467. package/src/surfaces/tab-strip.ts +200 -0
  468. package/src/surfaces/target-line.json +419 -0
  469. package/src/surfaces/target-line.ts +349 -0
  470. package/src/surfaces/toasts.json +189 -0
  471. package/src/surfaces/welcome.json +571 -0
  472. package/src/surfaces/welcome.ts +338 -0
  473. package/src/tabs/project-config.ts +111 -21
  474. package/src/tabs/tab.ts +52 -1
  475. package/src/types.ts +22 -0
  476. package/src/ui/ai-credentials-form.ts +104 -100
  477. package/src/ui/ai-managed-connect.ts +54 -36
  478. package/src/ui/ai-model-picker.ts +75 -47
  479. package/src/ui/cf-account-picker.ts +76 -141
  480. package/src/ui/color-selector.ts +80 -301
  481. package/src/ui/dynamic-slot.ts +43 -283
  482. package/src/ui/expression-editor.ts +797 -576
  483. package/src/ui/field-input.ts +8 -181
  484. package/src/ui/form-controls.ts +838 -366
  485. package/src/ui/formula-chips.ts +80 -85
  486. package/src/ui/kit.ts +33 -0
  487. package/src/ui/layers.ts +296 -593
  488. package/src/ui/media-picker.ts +203 -284
  489. package/src/ui/panel-resize.ts +251 -64
  490. package/src/ui/popover-surface.ts +153 -0
  491. package/src/ui/progress-modal.ts +22 -60
  492. package/src/ui/regions.ts +13 -7
  493. package/src/ui/schema-form.ts +906 -440
  494. package/src/ui/surface.ts +122 -0
  495. package/src/ui/unit-selector.ts +15 -131
  496. package/src/ui/value-source.ts +14 -0
  497. package/src/ui/virtual-window.ts +88 -9
  498. package/src/utils/canvas-media.ts +72 -0
  499. package/src/utils/edit-display.ts +7 -2
  500. package/src/utils/element-selectors.ts +69 -0
  501. package/src/utils/link-target.ts +2 -2
  502. package/src/utils/studio-utils.ts +0 -10
  503. package/src/view.ts +15 -0
  504. package/src/workspace/pane-derive.ts +36 -14
  505. package/src/workspace/workspace.ts +75 -6
  506. package/styles/canvas.css +72 -467
  507. package/styles/forced-colors.css +48 -82
  508. package/styles/forced-colors.json +41 -0
  509. package/styles/inspector.css +2 -1301
  510. package/styles/overlays.css +96 -2823
  511. package/styles/panels.css +6 -1423
  512. package/styles/shell-frame.css +272 -0
  513. package/styles/shell-frame.json +227 -0
  514. package/styles/shell.css +0 -1568
  515. package/styles/tokens.css +65 -136
  516. package/styles/tokens.json +84 -0
  517. package/dist/chunks/Overlay.dev-etqjwyf9.js +0 -23
  518. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  519. package/dist/chunks/cf-account-picker-en86v7x7.js +0 -163
  520. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  521. package/dist/chunks/components-zmx10t62.js +0 -21
  522. package/dist/chunks/content-source-48xg86wj.js +0 -49
  523. package/dist/chunks/convert-to-repeater-43tfn7cs.js +0 -268
  524. package/dist/chunks/editor-cptq5jp1.js +0 -37
  525. package/dist/chunks/entry-commands-e63f1xc0.js +0 -46
  526. package/dist/chunks/extension-sections-txv08xxg.js +0 -311
  527. package/dist/chunks/file-ops-wbh4hhsx.js +0 -48
  528. package/dist/chunks/files-3kfkwhk4.js +0 -93
  529. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  530. package/dist/chunks/focus-trap.esm-9t2drp0g.js +0 -1025
  531. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  532. package/dist/chunks/format-host-w16q81tf.js +0 -43
  533. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  534. package/dist/chunks/git-panel-532whr1y.js +0 -59
  535. package/dist/chunks/index-zqxmqxmh.js +0 -109
  536. package/dist/chunks/jx-validate-8er6gbxy.js +0 -19
  537. package/dist/chunks/layers-panel-07hm7g5j.js +0 -67
  538. package/dist/chunks/layers-q75tj2mf.js +0 -45
  539. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  540. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  541. package/dist/chunks/notify-yjm79n4s.js +0 -30
  542. package/dist/chunks/parse-24d0gay3.js +0 -19
  543. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  544. package/dist/chunks/publish-panel-v9st96ja.js +0 -29
  545. package/dist/chunks/quick-search-zccjp6gv.js +0 -66
  546. package/dist/chunks/references-3qx8fkyp.js +0 -29
  547. package/dist/chunks/right-panel-vm3b6kwy.js +0 -46
  548. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  549. package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +0 -18
  550. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  551. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  552. package/dist/chunks/sp-tooltip.dev-4sastdnw.js +0 -15
  553. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  554. package/dist/chunks/studio-0a5qrh01.js +0 -3
  555. package/dist/chunks/studio-0bq6eh7v.js +0 -12
  556. package/dist/chunks/studio-18j3bmcz.js +0 -14
  557. package/dist/chunks/studio-1ngbejft.js +0 -181
  558. package/dist/chunks/studio-4b5z1x43.js +0 -424
  559. package/dist/chunks/studio-4n2b5gzb.js +0 -357
  560. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  561. package/dist/chunks/studio-5fx3g9jg.js +0 -4325
  562. package/dist/chunks/studio-5myknm0a.js +0 -1903
  563. package/dist/chunks/studio-7afd21nw.js +0 -67
  564. package/dist/chunks/studio-7nte2hj4.js +0 -613
  565. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  566. package/dist/chunks/studio-8q517dfr.js +0 -24
  567. package/dist/chunks/studio-950k0dx6.js +0 -6939
  568. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  569. package/dist/chunks/studio-a0tswy0w.js +0 -58
  570. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  571. package/dist/chunks/studio-bgxt93ga.js +0 -62
  572. package/dist/chunks/studio-cmb03bg5.js +0 -13890
  573. package/dist/chunks/studio-d1ks410h.js +0 -175
  574. package/dist/chunks/studio-ef49pnzx.js +0 -387
  575. package/dist/chunks/studio-eqq1w638.js +0 -113
  576. package/dist/chunks/studio-ew0djmhg.js +0 -341
  577. package/dist/chunks/studio-gfgb8pe6.js +0 -1652
  578. package/dist/chunks/studio-h4rxscfc.js +0 -10
  579. package/dist/chunks/studio-jc994dnr.js +0 -1066
  580. package/dist/chunks/studio-kyh9avvv.js +0 -28
  581. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  582. package/dist/chunks/studio-mtfnaqs9.js +0 -659
  583. package/dist/chunks/studio-n6j9t10q.js +0 -318
  584. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  585. package/dist/chunks/studio-qcy05dp8.js +0 -1743
  586. package/dist/chunks/studio-qq6jym04.js +0 -53
  587. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  588. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  589. package/dist/chunks/studio-t7qb9db8.js +0 -665
  590. package/dist/chunks/studio-tmc5emrw.js +0 -8
  591. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  592. package/dist/chunks/studio-zczps70q.js +0 -378
  593. package/dist/chunks/studio-zqazsct2.js +0 -1823
  594. package/dist/chunks/workspace-fjx52ryv.js +0 -89
  595. package/src/panels/activity-bar.ts +0 -251
  596. package/src/panels/panel-scheduler.ts +0 -219
  597. package/src/panels/style-inputs.ts +0 -237
  598. package/src/panels/target-line.ts +0 -274
  599. package/src/panels/welcome-screen.ts +0 -346
  600. package/src/ui/button-group.ts +0 -102
  601. package/src/ui/choice-field.ts +0 -72
  602. package/src/ui/field-row.ts +0 -249
  603. package/src/ui/formula-palette.ts +0 -213
  604. package/src/ui/icons.ts +0 -52
  605. package/src/ui/jx-theme.ts +0 -130
  606. package/src/ui/spectrum.ts +0 -340
  607. package/src/ui/value-selector.ts +0 -174
  608. package/src/ui/widgets.ts +0 -172
  609. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  610. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  611. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  612. /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Ai-write-report.ts — what the model is told after a document write, whoever made it.
3
+ *
4
+ * Extracted from `ai-tools.ts`'s `applyAndValidate`, which used to own both halves of a document
5
+ * tool: the transaction and the verdict on it. The verdict is the half every document write needs
6
+ * — the seven hand-registered tree tools AND every command the assistant runs through
7
+ * `services/ai-command-tools.ts` — so it lives here, in two functions the caller brackets its write
8
+ * with:
9
+ *
10
+ * 1. {@link snapshotBeforeWrite} reads the document's schema errors and render state BEFORE the
11
+ * write, because the eval signal (ADR docs/ai-assistant-decision.md §6b) is "what did this edit
12
+ * newly introduce", not "is the document valid": a page that was already broken must not make
13
+ * every subsequent edit read as the culprit.
14
+ * 2. {@link reportDocumentWrite} compares AFTER the write, translating each new schema error into a
15
+ * fix hint the model can act on, running the render check only when rendering worked before,
16
+ * and appending the soft token-discipline hints to a success.
17
+ *
18
+ * The change stays applied either way (optimistic apply + undo, ADR §5); reporting the errors lets
19
+ * the agent loop self-correct on the next round.
20
+ *
21
+ * @license MIT
22
+ */
23
+
24
+ import type { ToolResult } from "@jxsuite/ai/tools";
25
+ import { toRaw } from "../reactivity";
26
+ import type { Tab } from "../tabs/tab";
27
+ import { flagHardcodedTokens, formatTokenHints } from "./token-lint";
28
+
29
+ /** A render probe's answer: rendered, or the message it threw. */
30
+ export type RenderVerdict = { ok: true } | { ok: false; error: string };
31
+
32
+ /** What a write reporter needs. Every member is what `registerAiTools` already takes by injection. */
33
+ export interface WriteReportDeps {
34
+ /** Schema errors for a document, as raw ajv sentences. */
35
+ validate: (doc: unknown) => Promise<string[]>;
36
+ /** The detached-DOM render probe, when the host has one. */
37
+ renderCheck?: ((doc: unknown) => Promise<RenderVerdict>) | undefined;
38
+ /** The project's design tokens, read per call so a project opened mid-session contributes. */
39
+ getProjectStyle?: (() => Record<string, string> | undefined) | undefined;
40
+ }
41
+
42
+ /** The document as it stood before a write, in the two respects the verdict compares. */
43
+ export interface WriteSnapshot {
44
+ errors: Set<string>;
45
+ renderOk: boolean;
46
+ }
47
+
48
+ /**
49
+ * Translate a raw JSON Schema validation error into a Jx-specific actionable message. The LLM needs
50
+ * concrete guidance on HOW to fix errors, not just what rule was violated. Shared with the
51
+ * project-level file tools (ai-project-tools.ts), which pre-validate Jx documents before writing.
52
+ *
53
+ * @param {string} rawError - Message from ajv (e.g. "/children/0/style: must NOT have additional
54
+ * property")
55
+ * @returns {string}
56
+ */
57
+ export function translateValidationError(rawError: string): string {
58
+ const lower = rawError.toLowerCase();
59
+
60
+ // Additional property — extract the offending key from the message if present
61
+ if (
62
+ lower.includes("must not have additional property") ||
63
+ lower.includes("additional properties")
64
+ ) {
65
+ return `${rawError}\n → Fix: Remove or move the unexpected property. Style properties must be camelCase (e.g. "backgroundColor", not "background-color"). Non-IDL HTML attributes (aria-*, data-*, role, ...) must go inside an "attributes" object: { "attributes": { "aria-label": "..." } }.`;
66
+ }
67
+
68
+ // Pattern — usually tagName hyphen rule
69
+ if (lower.includes("must match pattern")) {
70
+ return `${rawError}\n → Fix: Custom element tag names must contain a hyphen (e.g. "newsletter-form", "feature-card"). Standard HTML elements use their exact name (e.g. "div", "input", "button").`;
71
+ }
72
+
73
+ // Type error
74
+ if (lower.includes("must be string")) {
75
+ return `${rawError}\n → Fix: Wrap the value in quotes — all Jx property values should be strings. For example, use "10px" (string) not 10px (unquoted).`;
76
+ }
77
+
78
+ if (lower.includes("must be number") || lower.includes("must be integer")) {
79
+ return `${rawError}\n → Fix: Remove quotes from the numeric value — it should be a plain number, not a string.`;
80
+ }
81
+
82
+ if (lower.includes("must be object") || lower.includes("must be array")) {
83
+ return `${rawError}\n → Fix: The value must be an object/array (use {} or []), not a string or number.`;
84
+ }
85
+
86
+ if (lower.includes("must be boolean")) {
87
+ return `${rawError}\n → Fix: Use true or false without quotes for boolean values.`;
88
+ }
89
+
90
+ // Required property
91
+ if (lower.includes("must have required property")) {
92
+ return `${rawError}\n → Fix: Add the missing required property. Every Jx element must have at least a "tagName" field.`;
93
+ }
94
+
95
+ // Enum / allowed values
96
+ if (lower.includes("must be equal to one of the allowed values")) {
97
+ return `${rawError}\n → Fix: Change the value to one of the allowed options listed in the error.`;
98
+ }
99
+
100
+ return rawError;
101
+ }
102
+
103
+ /**
104
+ * Read the document's standing BEFORE a write: its schema errors and whether it renders.
105
+ *
106
+ * Reads the RAW document, not the reactive proxy, for the same reason `applyAndValidate` always
107
+ * did: the validator walks the whole tree, and walking a proxy subscribes whichever effect is
108
+ * running to every key of it.
109
+ *
110
+ * @param {Tab} tab
111
+ * @param {WriteReportDeps} deps
112
+ * @returns {Promise<WriteSnapshot>}
113
+ */
114
+ export async function snapshotBeforeWrite(tab: Tab, deps: WriteReportDeps): Promise<WriteSnapshot> {
115
+ const rawBefore = toRaw(tab.doc.document);
116
+ const errors = new Set(await deps.validate(rawBefore));
117
+ const rendered = deps.renderCheck ? await deps.renderCheck(rawBefore) : { ok: true };
118
+ return { errors, renderOk: rendered.ok };
119
+ }
120
+
121
+ /**
122
+ * The verdict on a write that has been applied: the NEW schema errors with fix hints, the render
123
+ * check (only when rendering worked before — a page that already failed to render is not this
124
+ * edit's fault), or a success carrying `summary` plus any token-discipline hints.
125
+ *
126
+ * The three sentences here are the ones the model has read since the tools were written; every
127
+ * bridged document command now answers with the same ones, which is what lets the prompt's error
128
+ * recovery guidance stay generic.
129
+ *
130
+ * @param {Tab} tab
131
+ * @param {WriteSnapshot} before - What {@link snapshotBeforeWrite} read.
132
+ * @param {string} summary - The sentence to return on success.
133
+ * @param {WriteReportDeps} deps
134
+ * @returns {Promise<ToolResult>}
135
+ */
136
+ export async function reportDocumentWrite(
137
+ tab: Tab,
138
+ before: WriteSnapshot,
139
+ summary: string,
140
+ deps: WriteReportDeps,
141
+ ): Promise<ToolResult> {
142
+ const rawAfter = toRaw(tab.doc.document);
143
+ const after = await deps.validate(rawAfter);
144
+ const newErrors = after.filter((e) => !before.errors.has(e));
145
+ if (newErrors.length > 0) {
146
+ const formatted = newErrors.map((e) => `- ${translateValidationError(e)}`).join("\n");
147
+ return {
148
+ success: false,
149
+ error: `Change applied, but it introduced schema errors. Fix these issues with follow-up edits:\n${formatted}`,
150
+ };
151
+ }
152
+
153
+ if (deps.renderCheck && before.renderOk) {
154
+ const renderResult = await deps.renderCheck(rawAfter);
155
+ if (!renderResult.ok) {
156
+ return {
157
+ success: false,
158
+ error: `Change applied and schema-valid, but it broke rendering. Fix with follow-up edits:\n- ${renderResult.error}`,
159
+ };
160
+ }
161
+ }
162
+
163
+ // Soft token-discipline hints (never fail the mutation)
164
+ const projectStyle = deps.getProjectStyle?.();
165
+ if (projectStyle) {
166
+ const findings = flagHardcodedTokens(rawAfter, projectStyle);
167
+ const hints = formatTokenHints(findings);
168
+ if (hints) {
169
+ return { success: true, summary: `${summary}\n\n${hints}` };
170
+ }
171
+ }
172
+
173
+ return { success: true, summary };
174
+ }
@@ -21,6 +21,11 @@ import { componentRegistry } from "../files/components";
21
21
  import { activeRegistry } from "../commands/active-registry";
22
22
  import { registerAiTools } from "./ai-tools";
23
23
  import { cancelAsk, registerAskTool, resetAsk } from "./ai-ask";
24
+ import {
25
+ commandToolBlurbs,
26
+ composeToolRegistries,
27
+ createCommandToolRegistry,
28
+ } from "./ai-command-tools";
24
29
  import { registerProjectTools } from "./ai-project-tools";
25
30
  import { registerImportTools, resetImportGuard } from "./ai-import-tools";
26
31
  import { createGatedToolRegistry } from "./gated-registry";
@@ -29,12 +34,14 @@ import { adoptProject } from "./project-adoption";
29
34
  import { abortImportRun, resetImportRuns } from "./import-run";
30
35
  import { runAgentLoop } from "./tool-executor";
31
36
  import { AI_TOOL_TIERS, buildSystemPrompt, toolActive } from "./ai-system-prompt";
37
+ import type { ExtensionCatalogSummary } from "./ai-system-prompt";
32
38
  import { getBaseUrl, getOpenAiKey } from "./ai-settings";
33
39
  import { preferredModel } from "./ai-models";
34
40
  import { pruneOrphanToolMessages, trimContext } from "./context-manager";
35
41
  import { renderCheck } from "./render-critic";
36
- import { openFileInTab, reloadFileInTab } from "../files/files";
37
- import { refreshExtensionUi } from "../format/format-host";
42
+ import { validateDoc } from "./jx-validate";
43
+ import { reloadFileInTab } from "../files/files";
44
+ import { getExtensionCatalog, refreshExtensionUi } from "../format/format-host";
38
45
  import * as sessionStore from "./ai-session-store";
39
46
 
40
47
  /**
@@ -91,7 +98,6 @@ export function createDocumentAssistant() {
91
98
  renderCheck: renderCheck as (
92
99
  doc: unknown,
93
100
  ) => Promise<{ ok: true } | { ok: false; error: string }>,
94
- openDocument: openFileInTab,
95
101
  getProjectStyle,
96
102
  findOpenTab,
97
103
  reloadTab: reloadFileInTab,
@@ -123,12 +129,15 @@ export function createDocumentAssistant() {
123
129
  sessionStore.moveSession("", root, sessionId);
124
130
  }
125
131
  },
126
- onProjectConfigWritten: async (config: ProjectConfig) => {
132
+ onProjectConfigWritten: async (config: ProjectConfig, text: string) => {
127
133
  /* Into the configuration document, not beside it. This used to assign a fresh object to
128
134
  `projectState.projectConfig`, leaving the document holding the previous configuration —
129
135
  and the next settings commit wrote that stale document back over the assistant's file.
130
- `adoptProjectConfig` is the one door for a config that reached disk another way. */
131
- await adoptProjectConfig(config);
136
+ `adoptProjectConfig` is the one door for a config that reached disk another way. The text
137
+ goes with it: the document derives the file's layout record from the bytes the tool wrote,
138
+ so the next settings commit is a one-line diff on the file as the model laid it out, not a
139
+ re-layout of it with the record of the file it read before (issue 331). */
140
+ await adoptProjectConfig(config, text);
132
141
  /* An `extensions` edit changes what the generated entry documents compose, and the backends
133
142
  regenerate them from project.json on demand — so without this the editor and the assistant
134
143
  both keep judging by the PREVIOUS project's schemas until the window reopens. */
@@ -150,7 +159,8 @@ export function createDocumentAssistant() {
150
159
  document: "an open document (use open_document first)",
151
160
  "document-tree":
152
161
  "an open document whose element tree the canvas is editing — Project Settings and the " +
153
- "grid editors are documents, but not trees to restructure",
162
+ "grid editors are documents, but not trees to restructure, and a page left in Code view " +
163
+ "returns to the canvas with set_canvas_mode",
154
164
  } as const;
155
165
 
156
166
  /**
@@ -189,7 +199,26 @@ export function createDocumentAssistant() {
189
199
  },
190
200
  ]),
191
201
  );
192
- const toolRegistry = createGatedToolRegistry(innerRegistry, availability);
202
+ /*
203
+ * The other kind of tool: every command record that declares `aiTool`, as a VIEW over the active
204
+ * registry (`services/ai-command-tools.ts`). Nothing is registered — the record IS the tool, its
205
+ * `when` / `enablement` is the gate, `registry.run` is the executor — so `enable_extension`,
206
+ * `delete_node` and the rest need no row in the tier table and no registrar here. The deps are
207
+ * the write reporter's, the same three the hand tree tools take, because a bridged document write
208
+ * is held to the same verdict (new schema errors, the render check, the token hints).
209
+ */
210
+ const commandTools = createCommandToolRegistry({
211
+ getProjectStyle,
212
+ getTab: () => activeTab.value,
213
+ renderCheck: renderCheck as (
214
+ doc: unknown,
215
+ ) => Promise<{ ok: true } | { ok: false; error: string }>,
216
+ validate: validateDoc,
217
+ });
218
+ const toolRegistry = composeToolRegistries(
219
+ createGatedToolRegistry(innerRegistry, availability),
220
+ commandTools,
221
+ );
193
222
 
194
223
  let controller: AbortController | null = null;
195
224
 
@@ -201,6 +230,19 @@ export function createDocumentAssistant() {
201
230
  .filter((e) => e.type === "file")
202
231
  .map((e) => e.path)
203
232
  : undefined;
233
+ /* The synchronous snapshot beside the async load, exactly as `getExtensions()` sits beside
234
+ `loadExtensions()`: `buildSystemPrompt` is a pure function and this is called per turn, so
235
+ the catalogue is read from the ONE cache the Extensions section also reads. Two caches would
236
+ be two answers to "what can this project turn on". */
237
+ const catalog: ExtensionCatalogSummary[] = [];
238
+ for (const entry of getExtensionCatalog()) {
239
+ catalog.push({
240
+ name: entry.name,
241
+ sections: entry.sections.map((section) => section.key),
242
+ ...(entry.title === undefined ? {} : { title: entry.title }),
243
+ ...(entry.description === undefined ? {} : { description: entry.description }),
244
+ });
245
+ }
204
246
  return buildSystemPrompt({
205
247
  document: tab ? toRaw(tab.doc.document) : undefined,
206
248
  projectConfig: (workspace.projectConfig as ProjectConfig | null) || undefined,
@@ -208,7 +250,16 @@ export function createDocumentAssistant() {
208
250
  projectRoot: workspace.projectRoot || undefined,
209
251
  hasProject: Boolean(workspace.projectRoot),
210
252
  canImport: Boolean(getPlatform().importSite),
253
+ /* The same reading the gate makes, so the prompt advertises exactly what `execute` will
254
+ honour. This was never passed: with Project Settings focused the prompt listed the seven
255
+ hand tree writers while the `document-tree` gate refused every one of them, and the model
256
+ spent a round learning it. */
257
+ treeEditable: treeEditable(),
258
+ /* Read per turn from the live registry — a projected tool the gate will honour this round is
259
+ listed this round, and one it will not is not. */
260
+ commandTools: commandToolBlurbs(activeRegistry()),
211
261
  ...(inventory && inventory.length > 0 ? { fileInventory: inventory } : {}),
262
+ ...(catalog.length > 0 ? { extensionCatalog: catalog } : {}),
212
263
  });
213
264
  }
214
265
 
@@ -12,22 +12,29 @@
12
12
  * in-flight (gitStatus)"]` — so the slow subsystem identifies itself.
13
13
  *
14
14
  * Nothing here polls a subsystem it does not own. Each source is a function the owning module
15
- * already had to write for its own reasons:
15
+ * already had to write for its own reasons.
16
+ *
17
+ * There WAS a seventh, `panel-scheduler.pendingSchedulers()`, and it went with the scheduler. It
18
+ * reported a panel with an animation frame queued or a render withheld while a field had focus —
19
+ * both facts about a lit dock repainting itself. The Navigator and the Inspector are documents now
20
+ * (`surfaces/navigator-dock.json`, `surfaces/inspector-dock.json`): a projection is written
21
+ * synchronously and a binding whose value did not move writes nothing, so there is no queued frame
22
+ * to be outstanding and no withheld render to wait for. The panel bodies that ARE still lit are
23
+ * painted synchronously from the same call.
16
24
  *
17
25
  * 1. `store.rendersInFlight()` — renderers mid-paint.
18
- * 2. `panel-scheduler.pendingSchedulers()` — panels with a frame queued or a render withheld.
19
- * 3. `iframe-host.canvasIdleBlockers()` — per host: unacked generations and patches, plus the frame's
26
+ * 2. `iframe-host.canvasIdleBlockers()` — per host: unacked generations and patches, plus the frame's
20
27
  * own cross-realm report of fonts, running animations and pending image retries.
21
- * 4. `platform.platformInFlight()` — unsettled PAL calls, counted at the one seam every adapter and
28
+ * 3. `platform.platformInFlight()` — unsettled PAL calls, counted at the one seam every adapter and
22
29
  * all thirty-odd `git*`/fs/fetch methods pass through.
23
- * 5. `layers.overlayIdleBlockers()` — overlays still in transition. Only the SETTLING window counts: a
30
+ * 4. `layers.overlayIdleBlockers()` — overlays still in transition. Only the SETTLING window counts: a
24
31
  * resting toast is not a blocker, which is what lets `toastsAreHeld()` hold one open for a
25
32
  * capture without `probeIdle()` waiting forever alongside it (plan §13.7's named exception).
26
- * 6. `activity-panel.activityIdleBlockers()` — operations still RUNNING in the Activity tab. Not a
33
+ * 5. `activity-panel.activityIdleBlockers()` — operations still RUNNING in the Activity tab. Not a
27
34
  * duplicate of `platform`: an activity spans a whole operation (an install, a deploy, a clone)
28
35
  * across many PAL calls, so the gaps between them look quiet at the seam while the operation is
29
36
  * plainly mid-flight. A finished entry never blocks — the list stays on screen forever.
30
- * 7. `grid-idle.gridIdleBlockers()` — tables still building, or built but not yet showing the
37
+ * 6. `grid-idle.gridIdleBlockers()` — tables still building, or built but not yet showing the
31
38
  * selection range `selectableRange: 1` gives them. Nothing else covered Tabulator: a grid
32
39
  * command resolves when the panel mounts, which is several frames before the table is drawn.
33
40
  *
@@ -37,7 +44,6 @@
37
44
 
38
45
  import { rendersInFlight } from "../store";
39
46
  import { activityIdleBlockers } from "../panels/activity-panel";
40
- import { pendingSchedulers } from "../panels/panel-scheduler";
41
47
  import { canvasIdleBlockers } from "../canvas/iframe-host";
42
48
  import { platformInFlight } from "../platform";
43
49
  import { overlayIdleBlockers } from "../ui/layers";
@@ -45,7 +51,7 @@ import { gridIdleBlockers } from "../grid/grid-idle";
45
51
 
46
52
  /** One subsystem that can be outstanding, and its account of why. */
47
53
  export interface IdleSource {
48
- /** Stable name — `render`, `panels`, `canvas`, `platform`, `overlay`. */
54
+ /** Stable name — `render`, `canvas`, `platform`, `overlay`. */
49
55
  readonly name: string;
50
56
  /** Empty when quiet; otherwise one human-readable line per outstanding item. */
51
57
  blockers: () => readonly string[];
@@ -73,7 +79,7 @@ export class NotIdleError extends Error {
73
79
  }
74
80
 
75
81
  /**
76
- * The seven live sources.
82
+ * The six live sources.
77
83
  *
78
84
  * Built per call rather than held in a module constant so a test can substitute one without
79
85
  * unpicking the others, and so a second window's hosts are never read through the first window's
@@ -88,10 +94,6 @@ export function defaultIdleSources(): IdleSource[] {
88
94
  },
89
95
  name: "render",
90
96
  },
91
- {
92
- blockers: () => pendingSchedulers().map((panel) => `panels: ${panel}`),
93
- name: "panels",
94
- },
95
97
  { blockers: canvasIdleBlockers, name: "canvas" },
96
98
  {
97
99
  blockers: () => {
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Live authoring of Studio's own chrome.
3
+ *
4
+ * Studio's surfaces are Jx documents (`src/surfaces/*.json`) and its controls are the kit's
5
+ * (`packages/ui/components/*.json`), so both are things Studio can open and edit. This is what
6
+ * closes the loop: a saved surface document re-mounts every root drawn from it, and a saved kit
7
+ * component redefines the element and re-mounts every root that used it, so the edit shows in the
8
+ * shell the reader is standing in (studio-ui-guidelines.md §9.3, embedding.md §7).
9
+ *
10
+ * **The lane is keyed on the saved PATH, and that is the whole of how it stays inert.** A save is
11
+ * something to act on only when the file, joined to the open project's root, is one of the two
12
+ * places the chrome comes from. Any other project — a site, a starter, the examples — saves files
13
+ * this never looks at, and the shipped app never reads its chrome from disk: the document that
14
+ * re-mounts is the one the tab just wrote, handed over by the save path, never read back.
15
+ *
16
+ * Two things are deliberately NOT here. The lane does not watch the filesystem: an edit made
17
+ * outside Studio reaches the shell on the next reload, as it always did, because a watcher is a
18
+ * second writer racing the tab. And it does not diff: a saved document is re-registered whole and
19
+ * every root re-mounted, because a surface's host scope is reused (`SurfaceMount.remount`) and only
20
+ * the surface-local state resets, which is the contract §9.3 gives the registry.
21
+ *
22
+ * A kit redefinition reaches the canvas frames too, with the FILE's URL under the project as its
23
+ * base: the frame draws a project's elements from the project's own files, so a sibling `$ref` in
24
+ * the definition must resolve to the project's copy, not to the bundle's. The frame answers the
25
+ * definition's `jx-ui:` sidecars from the loaders it registered at boot (`iframe-entry.ts`), one
26
+ * chunk per behaviour on first use.
27
+ *
28
+ * @docs extending/ui-kit
29
+ */
30
+ import { redefineElement } from "@jxsuite/runtime";
31
+ import { KIT_BASE } from "@jxsuite/ui";
32
+ import type { JxDocument } from "@jxsuite/schema/types";
33
+ import { mountsOf, mountsUsing } from "./surface-registry";
34
+ import { registerSurface, surfaceDocument } from "../ui/surface";
35
+ import { documentBase } from "../canvas/canvas-origin";
36
+
37
+ /** What a saved file IS to the running shell. */
38
+ export type LiveTarget =
39
+ | { readonly kind: "surface"; readonly name: string }
40
+ | { readonly kind: "element"; readonly tag: string };
41
+
42
+ /** Where a surface document lives, from any root that contains it. */
43
+ const SURFACE_PATH = /\/packages\/studio\/src\/surfaces\/([\w-]+)\.json$/;
44
+ /** Where a kit component lives, from any root that contains it. */
45
+ const ELEMENT_PATH = /\/packages\/ui\/components\/(jx-[\w-]+)\.json$/;
46
+
47
+ /**
48
+ * Join a project root and a path the way the platform reports them, and normalise the separators so
49
+ * a Windows root and a POSIX-relative path meet in one spelling.
50
+ */
51
+ function joined(projectRoot: string, path: string): string {
52
+ const root = projectRoot.replaceAll("\\", "/").replace(/\/+$/, "");
53
+ const rel = path.replaceAll("\\", "/").replace(/^\.?\//, "");
54
+ return `${root}/${rel}`;
55
+ }
56
+
57
+ /**
58
+ * Which surface or element a saved path is, or null for every other file.
59
+ *
60
+ * Matched by suffix against the root JOINED to the path rather than by which project is open, so
61
+ * the same answer comes from the kit opened as its own project (`components/jx-tree.json` under
62
+ * `packages/ui`), from Studio opened as one (`src/surfaces/menu.json` under `packages/studio`), or
63
+ * from any root above them. A path that is neither — including every file of every other project —
64
+ * is null, and null is the lane doing nothing.
65
+ *
66
+ * @param projectRoot The open project's root, as the platform reports it.
67
+ * @param path The saved path, relative to that root.
68
+ */
69
+ export function liveSurfaceTarget(
70
+ projectRoot: string | null | undefined,
71
+ path: string | null | undefined,
72
+ ): LiveTarget | null {
73
+ if (!projectRoot || !path) {
74
+ return null;
75
+ }
76
+ const full = joined(projectRoot, path);
77
+ const surface = SURFACE_PATH.exec(full);
78
+ if (surface) {
79
+ return { kind: "surface", name: surface[1]! };
80
+ }
81
+ const element = ELEMENT_PATH.exec(full);
82
+ if (element) {
83
+ return { kind: "element", tag: element[1]! };
84
+ }
85
+ return null;
86
+ }
87
+
88
+ /** What one save did. */
89
+ export interface LiveSurfaceResult {
90
+ readonly target: LiveTarget;
91
+ /** How many roots were re-mounted. Zero is a document nothing on screen was drawn from. */
92
+ readonly remounted: number;
93
+ /** How many canvas frames were told of an element's redefinition. Absent for a surface. */
94
+ readonly canvases?: number;
95
+ /** Why nothing was applied, when nothing was. */
96
+ readonly refused?: string;
97
+ }
98
+
99
+ /**
100
+ * The URL a frame resolves a saved kit component against: the file's own URL under the project,
101
+ * which is where the frame fetched the definition it holds and where its sibling `$ref`s live.
102
+ *
103
+ * @param projectRoot The open project's root.
104
+ * @param path The saved path, relative to it.
105
+ */
106
+ export function canvasBaseFor(projectRoot: string, path: string): string {
107
+ return new URL(path.replaceAll("\\", "/").replace(/^\.?\//, ""), documentBase(projectRoot)).href;
108
+ }
109
+
110
+ /**
111
+ * Apply a saved document to the running shell.
112
+ *
113
+ * A surface is re-registered under its name — the same call the bundle makes at boot, so the
114
+ * runtime's own resolution paths see the new document too — and every root of that name is
115
+ * re-mounted. An element is redefined through the runtime (embedding.md §7) and every root whose
116
+ * render instantiated it is re-mounted, which is what turns a redefinition into something visible:
117
+ * an instance already connected keeps the definition it rendered until it is re-mounted.
118
+ *
119
+ * A surface name nothing has registered is refused rather than registered: a new file under
120
+ * `src/surfaces/` has no adapter to mount it, so registering it would promise a mount nothing will
121
+ * make. An element whose document names a different tag than its file is refused too — the file is
122
+ * what the kit's registry keys on, and a document that disagrees with its own name is a mistake to
123
+ * report, not one to define under either spelling.
124
+ *
125
+ * @param target What the saved file is.
126
+ * @param doc The document the tab just wrote.
127
+ */
128
+ export async function applyLiveSave(
129
+ target: LiveTarget,
130
+ doc: JxDocument,
131
+ ): Promise<LiveSurfaceResult> {
132
+ if (target.kind === "surface") {
133
+ if (!surfaceDocument(target.name)) {
134
+ return { refused: `no surface is registered as "${target.name}"`, remounted: 0, target };
135
+ }
136
+ registerSurface(target.name, doc);
137
+ const roots = mountsOf(target.name);
138
+ await Promise.all(roots.map((m) => m.remount()));
139
+ return { remounted: roots.length, target };
140
+ }
141
+ if (doc.tagName !== target.tag) {
142
+ return {
143
+ refused: `the document names <${String(doc.tagName)}>, but the file is ${target.tag}.json`,
144
+ remounted: 0,
145
+ target,
146
+ };
147
+ }
148
+ await redefineElement(doc, KIT_BASE);
149
+ const roots = mountsUsing(target.tag);
150
+ await Promise.all(roots.map((m) => m.remount()));
151
+ return { remounted: roots.length, target };
152
+ }
153
+
154
+ /** The two channels a save's outcome is said on. A refusal is a problem; a re-mount is a toast. */
155
+ export interface LiveSurfaceNotifier {
156
+ info: (message: string, options: { key: string; source: string }) => void;
157
+ warn: (message: string, options: { key: string; source: string; tier: "problem" }) => void;
158
+ }
159
+
160
+ /**
161
+ * What the lane needs from the shell, as the records themselves rather than closures over them, so
162
+ * the bootstrap hands over objects it already holds and writes no function of its own.
163
+ */
164
+ export interface LiveSurfaceDeps {
165
+ /** The workspace record; `projectRoot` is read at save time, never captured. */
166
+ workspace: { readonly projectRoot: string | null };
167
+ notify: LiveSurfaceNotifier;
168
+ /**
169
+ * Redefine an element in every live canvas frame and render them; answers how many were told.
170
+ * `canvas-render.ts`'s `redefineElementOnCanvases`, injected so this module imports no canvas.
171
+ */
172
+ redefineOnCanvases: (doc: JxDocument, base: string) => number;
173
+ }
174
+
175
+ /** The sentence a result is said in. Exported so the wording is tested, not only the branch. */
176
+ export function liveSaveNotice(result: LiveSurfaceResult): {
177
+ key: string;
178
+ level: "info" | "warn";
179
+ message: string;
180
+ } {
181
+ const what =
182
+ result.target.kind === "surface" ? `surface ${result.target.name}` : result.target.tag;
183
+ const key = `live-chrome:${what}`;
184
+ if (result.refused) {
185
+ return { key, level: "warn", message: `Not applied to the running shell: ${result.refused}.` };
186
+ }
187
+ const canvases =
188
+ result.canvases === undefined || result.canvases === 0
189
+ ? ""
190
+ : result.canvases === 1
191
+ ? " and on the canvas"
192
+ : ` and on ${result.canvases} canvases`;
193
+ if (result.remounted === 0) {
194
+ return {
195
+ key,
196
+ level: "info",
197
+ message: `${what} saved; nothing in the shell is drawn from it${canvases ? `, redefined${canvases}` : ""}.`,
198
+ };
199
+ }
200
+ const places = result.remounted === 1 ? "1 place" : `${result.remounted} places`;
201
+ return {
202
+ key,
203
+ level: "info",
204
+ message: `${what} saved and re-mounted in ${places}${canvases}.`,
205
+ };
206
+ }
207
+
208
+ /**
209
+ * The save listener: decide whether the saved file is chrome, and if it is, apply it and say so.
210
+ *
211
+ * Returns the result, or null when the save was not chrome, so a caller — and a test — can tell
212
+ * "nothing to do" from "did nothing".
213
+ *
214
+ * @param deps The shell's workspace record and notifier.
215
+ */
216
+ export function createLiveSurfaceSaver(
217
+ deps: LiveSurfaceDeps,
218
+ ): (path: string | null, doc: JxDocument | null) => Promise<LiveSurfaceResult | null> {
219
+ return async (path, doc) => {
220
+ const root = deps.workspace.projectRoot;
221
+ const target = liveSurfaceTarget(root, path);
222
+ if (!target || !doc || !root || !path) {
223
+ return null;
224
+ }
225
+ let result = await applyLiveSave(target, doc);
226
+ if (target.kind === "element" && !result.refused) {
227
+ result = { ...result, canvases: deps.redefineOnCanvases(doc, canvasBaseFor(root, path)) };
228
+ }
229
+ const notice = liveSaveNotice(result);
230
+ if (notice.level === "warn") {
231
+ deps.notify.warn(notice.message, { key: notice.key, source: "Studio", tier: "problem" });
232
+ } else {
233
+ deps.notify.info(notice.message, { key: notice.key, source: "Studio" });
234
+ }
235
+ return result;
236
+ };
237
+ }