@jxsuite/studio 4.1.0 → 5.0.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 (607) 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-fyf63pmy.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-2w1f35qs.js +18 -0
  15. package/dist/chunks/content-source-3wqeas45.js +46 -0
  16. package/dist/chunks/convert-to-repeater-d0cgnb6d.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-d6g50j7s.js +42 -0
  20. package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
  21. package/dist/chunks/file-ops-3btj6st0.js +47 -0
  22. package/dist/chunks/files-ef8fgs3w.js +72 -0
  23. package/dist/chunks/format-host-3c33nwr8.js +40 -0
  24. package/dist/chunks/fs-events-13tj6sex.js +18 -0
  25. package/dist/chunks/git-panel-4wp2rn9b.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-jgesd924.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-1nq5evsh.js +29 -0
  37. package/dist/chunks/layers-panel-ar2gh90g.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-2qbetq73.js +33 -0
  41. package/dist/chunks/menu-q99sy9rf.js +285 -0
  42. package/dist/chunks/menu-rf7n72mf.js +14 -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-98f7sr3g.js +27 -0
  52. package/dist/chunks/quick-search-srzz83k2.js +45 -0
  53. package/dist/chunks/references-n553f0e1.js +26 -0
  54. package/dist/chunks/right-panel-rrgx2dn3.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-18avnhjp.js +2430 -0
  60. package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
  61. package/dist/chunks/{studio-msd847zn.js → studio-25hkdrkw.js} +357 -86
  62. package/dist/chunks/studio-26d7myd1.js +258 -0
  63. package/dist/chunks/{studio-4r1pv6zf.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/studio-3gxv60tn.js +422 -0
  65. package/dist/chunks/{studio-fbf92ckf.js → studio-3hxkd92t.js} +275 -163
  66. package/dist/chunks/studio-4m0haseg.js +185 -0
  67. package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
  68. package/dist/chunks/{studio-1wagb550.js → studio-5523bpzt.js} +11 -11
  69. package/dist/chunks/{studio-x4qkdat5.js → studio-57mf66w2.js} +1749 -2481
  70. package/dist/chunks/studio-5jy81t3s.js +17463 -0
  71. package/dist/chunks/studio-5rt7sqa0.js +1168 -0
  72. package/dist/chunks/studio-5te5tqng.js +81 -0
  73. package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
  74. package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
  75. package/dist/chunks/studio-6xa21ej9.js +28 -0
  76. package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
  77. package/dist/chunks/{studio-ahn3pdgx.js → studio-79y5sz51.js} +52 -38
  78. package/dist/chunks/{studio-gcye7qka.js → studio-7e11jpa9.js} +21 -21
  79. package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
  80. package/dist/chunks/studio-7xptrg0j.js +954 -0
  81. package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
  82. package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
  83. package/dist/chunks/studio-8qtrpzr3.js +839 -0
  84. package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
  85. package/dist/chunks/studio-9xxz1q69.js +1356 -0
  86. package/dist/chunks/studio-akbww0j5.js +13615 -0
  87. package/dist/chunks/{studio-x813zp48.js → studio-arfpe389.js} +30 -30
  88. package/dist/chunks/{studio-trxrabqf.js → studio-az3zd49t.js} +475 -283
  89. package/dist/chunks/studio-cpvb2ed1.js +1171 -0
  90. package/dist/chunks/{studio-f3wqjtk5.js → studio-d0300636.js} +5076 -18
  91. package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
  92. package/dist/chunks/studio-d1ja2x9r.js +362 -0
  93. package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
  94. package/dist/chunks/{studio-3bqpr0zh.js → studio-em9nw8eh.js} +299 -110
  95. package/dist/chunks/studio-erdatzvp.js +1190 -0
  96. package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
  97. package/dist/chunks/studio-fabxk6r9.js +2811 -0
  98. package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
  99. package/dist/chunks/{studio-dm19q43r.js → studio-hhvs4sdg.js} +10 -10
  100. package/dist/chunks/{studio-q9jd1a60.js → studio-kcgff4r0.js} +15 -18
  101. package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
  102. package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
  103. package/dist/chunks/studio-pm6hgy7r.js +4763 -0
  104. package/dist/chunks/studio-q0a3yk4n.js +33 -0
  105. package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
  106. package/dist/chunks/studio-qahxvnan.js +111 -0
  107. package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
  108. package/dist/chunks/{studio-2b946z26.js → studio-rkstz940.js} +3658 -6134
  109. package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
  110. package/dist/chunks/studio-rpyah2ew.js +2805 -0
  111. package/dist/chunks/studio-rs76k67r.js +12 -0
  112. package/dist/chunks/{studio-jkftxyvz.js → studio-s6z853aq.js} +5858 -2152
  113. package/dist/chunks/{studio-6yw4y3my.js → studio-sgdc5pfc.js} +8 -8
  114. package/dist/chunks/studio-tb3ev01j.js +763 -0
  115. package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
  116. package/dist/chunks/studio-vhv5tgxm.js +51 -0
  117. package/dist/chunks/{studio-qjy2z9bv.js → studio-vz68yn9e.js} +32 -137
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/{studio-b55y6ewx.js → studio-x3rty6tr.js} +58 -58
  120. package/dist/chunks/studio-xsykpvsh.js +8448 -0
  121. package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
  122. package/dist/chunks/studio-yxa81f45.js +12 -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-wrew8zk4.js +69 -0
  133. package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
  134. package/dist/iframe-entry.js +1780 -667
  135. package/dist/studio.js +52819 -36480
  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 +310 -117
  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 +369 -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 +165 -8
  178. package/src/content/entry-commands.ts +16 -23
  179. package/src/content/entry-editor.ts +144 -101
  180. package/src/editor/canvas-slash-bridge.ts +2 -2
  181. package/src/editor/context-menu.ts +49 -200
  182. package/src/editor/convert-to-component.ts +42 -82
  183. package/src/editor/convert-to-repeater.ts +132 -173
  184. package/src/editor/inline-edit.ts +11 -0
  185. package/src/editor/shortcuts.ts +65 -26
  186. package/src/editor/slash-menu.ts +150 -157
  187. package/src/files/file-ops.ts +117 -11
  188. package/src/files/files.ts +943 -660
  189. package/src/files/json-layout.ts +474 -0
  190. package/src/files/serialize-document.ts +8 -1
  191. package/src/format/convert-file.ts +16 -10
  192. package/src/format/format-host.ts +50 -1
  193. package/src/github/github-auth.ts +71 -29
  194. package/src/github/github-publish.ts +57 -65
  195. package/src/grid/cell-editors.ts +46 -4
  196. package/src/grid/cell-popovers.ts +65 -62
  197. package/src/grid/grid-open.ts +86 -64
  198. package/src/grid/grid-panel.ts +390 -469
  199. package/src/grid/redirects-grid.ts +40 -44
  200. package/src/hosting/layout.ts +2 -0
  201. package/src/i18n/i18n-commands.ts +127 -62
  202. package/src/media/media-pane.ts +83 -133
  203. package/src/new-project/add-repo-modal.ts +125 -176
  204. package/src/new-project/import-tab.ts +181 -252
  205. package/src/new-project/location-fields.ts +93 -160
  206. package/src/new-project/new-project-modal.ts +376 -367
  207. package/src/packages/jxsuite-update.ts +76 -18
  208. package/src/panels/activity-panel.ts +137 -104
  209. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  210. package/src/panels/ai-chat/chat-view.ts +307 -472
  211. package/src/panels/ai-chat/composer.ts +175 -163
  212. package/src/panels/ai-chat/sessions-view.ts +31 -62
  213. package/src/panels/ai-panel.ts +210 -185
  214. package/src/panels/block-action-bar.ts +437 -643
  215. package/src/panels/bottom-dock.ts +112 -47
  216. package/src/panels/chat-panel.ts +19 -14
  217. package/src/panels/data-explorer.ts +141 -102
  218. package/src/panels/data-grid.ts +183 -150
  219. package/src/panels/dnd.ts +75 -20
  220. package/src/panels/editors.ts +26 -19
  221. package/src/panels/elements-panel.ts +243 -186
  222. package/src/panels/empty-state.ts +26 -42
  223. package/src/panels/events-panel.ts +950 -729
  224. package/src/panels/formula-workspace.ts +434 -207
  225. package/src/panels/frontmatter-fields.ts +185 -153
  226. package/src/panels/frontmatter-panel.ts +411 -187
  227. package/src/panels/git-diff-open.ts +148 -0
  228. package/src/panels/git-panel.ts +679 -605
  229. package/src/panels/head-panel.ts +617 -435
  230. package/src/panels/i18n-panel.ts +153 -133
  231. package/src/panels/imports-panel.ts +388 -414
  232. package/src/panels/jump-bar.ts +174 -147
  233. package/src/panels/layers-panel.ts +785 -671
  234. package/src/panels/left-panel.ts +166 -94
  235. package/src/panels/navigator-panels.ts +1 -1
  236. package/src/panels/pane-context.ts +529 -677
  237. package/src/panels/pane-grid.ts +265 -241
  238. package/src/panels/panel-registry.ts +15 -4
  239. package/src/panels/problems-panel.ts +177 -99
  240. package/src/panels/properties-panel.ts +1525 -966
  241. package/src/panels/provenance.ts +31 -113
  242. package/src/panels/quick-search.ts +217 -172
  243. package/src/panels/right-panel.ts +135 -169
  244. package/src/panels/seo-modal.ts +346 -167
  245. package/src/panels/settings-menu.ts +109 -646
  246. package/src/panels/settings-pane.ts +102 -86
  247. package/src/panels/signals-panel.ts +1318 -1172
  248. package/src/panels/statement-editor.ts +556 -428
  249. package/src/panels/style-panel.ts +1367 -630
  250. package/src/panels/style-utils.ts +36 -32
  251. package/src/panels/stylebook-doc.ts +30 -73
  252. package/src/panels/stylebook-layers-panel.ts +202 -109
  253. package/src/panels/stylebook-panel.ts +124 -88
  254. package/src/panels/tab-strip.ts +385 -287
  255. package/src/platforms/cloud.ts +106 -16
  256. package/src/platforms/devserver.ts +13 -0
  257. package/src/publish/deploy-checklist.ts +124 -78
  258. package/src/publish/publish-commands.ts +4 -12
  259. package/src/publish/publish-panel.ts +134 -328
  260. package/src/services/a11y-report.ts +100 -43
  261. package/src/services/ai-command-tools.ts +468 -0
  262. package/src/services/ai-session-store.ts +6 -0
  263. package/src/services/ai-system-prompt.ts +110 -18
  264. package/src/services/ai-tools.ts +28 -143
  265. package/src/services/ai-write-report.ts +174 -0
  266. package/src/services/document-assistant.ts +50 -2
  267. package/src/services/idle.ts +16 -14
  268. package/src/services/live-surfaces.ts +237 -0
  269. package/src/services/model-uri.ts +75 -0
  270. package/src/services/notify.ts +63 -6
  271. package/src/services/popover-report.ts +325 -0
  272. package/src/services/surface-registry.ts +56 -0
  273. package/src/services/tool-executor.ts +6 -0
  274. package/src/settings/contexts-section.ts +301 -299
  275. package/src/settings/contributed-section.ts +361 -222
  276. package/src/settings/css-vars-editor.ts +320 -325
  277. package/src/settings/defs-editor.ts +572 -535
  278. package/src/settings/dependencies-editor.ts +79 -107
  279. package/src/settings/extension-commands.ts +379 -0
  280. package/src/settings/extension-rows.ts +113 -0
  281. package/src/settings/extensions-section.ts +287 -0
  282. package/src/settings/general-settings.ts +130 -181
  283. package/src/settings/head-editor.ts +10 -305
  284. package/src/settings/locales-section.ts +146 -196
  285. package/src/settings/preferences-accounts.ts +1 -1
  286. package/src/settings/preferences-dialog.ts +350 -330
  287. package/src/settings/project-sections.ts +108 -181
  288. package/src/settings/schema-field-ui.ts +11 -399
  289. package/src/settings/section-registry.ts +8 -1
  290. package/src/settings/settings-document.ts +31 -29
  291. package/src/shell/tree.ts +42 -87
  292. package/src/shell.ts +48 -36
  293. package/src/studio.ts +90 -67
  294. package/src/style/token-ref.ts +0 -39
  295. package/src/surfaces/about.json +263 -0
  296. package/src/surfaces/about.ts +163 -0
  297. package/src/surfaces/add-repo.json +486 -0
  298. package/src/surfaces/add-repo.ts +236 -0
  299. package/src/surfaces/ai-chat.json +2185 -0
  300. package/src/surfaces/ai-chat.ts +549 -0
  301. package/src/surfaces/ai-credentials-form.json +332 -0
  302. package/src/surfaces/ai-credentials-form.ts +151 -0
  303. package/src/surfaces/ai-managed-connect.json +108 -0
  304. package/src/surfaces/ai-managed-connect.ts +123 -0
  305. package/src/surfaces/ai-model-picker.json +114 -0
  306. package/src/surfaces/ai-model-picker.ts +139 -0
  307. package/src/surfaces/block-action-bar.json +640 -0
  308. package/src/surfaces/block-action-bar.ts +368 -0
  309. package/src/surfaces/bottom-dock.json +154 -0
  310. package/src/surfaces/bottom-dock.ts +125 -0
  311. package/src/surfaces/canvas-stage.json +444 -0
  312. package/src/surfaces/canvas-stage.ts +253 -0
  313. package/src/surfaces/cf-account-picker.json +300 -0
  314. package/src/surfaces/cf-account-picker.ts +214 -0
  315. package/src/surfaces/commandbar.json +984 -0
  316. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
  317. package/src/surfaces/convert-repeater.json +309 -0
  318. package/src/surfaces/convert-repeater.ts +276 -0
  319. package/src/surfaces/data-actions.json +157 -0
  320. package/src/surfaces/data-actions.ts +115 -0
  321. package/src/surfaces/dialog.json +289 -0
  322. package/src/surfaces/dialog.ts +343 -0
  323. package/src/surfaces/diff-toolbar.json +266 -0
  324. package/src/surfaces/diff-toolbar.ts +139 -0
  325. package/src/surfaces/doc-header.json +739 -0
  326. package/src/surfaces/doc-header.ts +223 -0
  327. package/src/surfaces/empty-state.json +152 -0
  328. package/src/surfaces/empty-state.ts +173 -0
  329. package/src/surfaces/entry-editor.json +281 -0
  330. package/src/surfaces/entry-editor.ts +191 -0
  331. package/src/surfaces/expression-editor.json +977 -0
  332. package/src/surfaces/expression-editor.ts +266 -0
  333. package/src/surfaces/files-panel.json +592 -0
  334. package/src/surfaces/files-panel.ts +301 -0
  335. package/src/surfaces/formula-palette.json +364 -0
  336. package/src/surfaces/formula-palette.ts +340 -0
  337. package/src/surfaces/git-panel.json +1822 -0
  338. package/src/surfaces/git-panel.ts +272 -0
  339. package/src/surfaces/github-auth.json +112 -0
  340. package/src/surfaces/github-auth.ts +139 -0
  341. package/src/surfaces/github-publish.json +206 -0
  342. package/src/surfaces/github-publish.ts +169 -0
  343. package/src/surfaces/grid-cell.json +218 -0
  344. package/src/surfaces/grid-cell.ts +120 -0
  345. package/src/surfaces/grid-open.json +147 -0
  346. package/src/surfaces/grid-open.ts +87 -0
  347. package/src/surfaces/grid-panel.json +706 -0
  348. package/src/surfaces/grid-panel.ts +206 -0
  349. package/src/surfaces/grid-replace.json +179 -0
  350. package/src/surfaces/grid-replace.ts +89 -0
  351. package/src/surfaces/grid-views.json +446 -0
  352. package/src/surfaces/grid-views.ts +172 -0
  353. package/src/surfaces/inspector-dock.json +187 -0
  354. package/src/surfaces/inspector-dock.ts +161 -0
  355. package/src/surfaces/jump-bar.json +243 -0
  356. package/src/surfaces/jump-bar.ts +129 -0
  357. package/src/surfaces/jxsuite-update.json +146 -0
  358. package/src/surfaces/jxsuite-update.ts +149 -0
  359. package/src/surfaces/library-pane.json +1509 -0
  360. package/src/surfaces/library-pane.ts +363 -0
  361. package/src/surfaces/logic-panel.json +1949 -0
  362. package/src/surfaces/logic-panel.ts +369 -0
  363. package/src/surfaces/logic-workspace.json +685 -0
  364. package/src/surfaces/logic-workspace.ts +238 -0
  365. package/src/surfaces/media-browser.json +303 -0
  366. package/src/surfaces/media-browser.ts +145 -0
  367. package/src/surfaces/media-field.json +163 -0
  368. package/src/surfaces/media-field.ts +116 -0
  369. package/src/surfaces/media-pane.json +513 -0
  370. package/src/surfaces/media-pane.ts +197 -0
  371. package/src/surfaces/menu.json +232 -0
  372. package/src/surfaces/menu.ts +375 -0
  373. package/src/surfaces/navigator-dock.json +113 -0
  374. package/src/surfaces/navigator-dock.ts +130 -0
  375. package/src/surfaces/new-project.json +1654 -0
  376. package/src/surfaces/new-project.ts +411 -0
  377. package/src/surfaces/palette.json +535 -0
  378. package/src/surfaces/pane-context.json +1497 -0
  379. package/src/surfaces/pane-context.ts +513 -0
  380. package/src/surfaces/pane-grid.json +188 -0
  381. package/src/surfaces/pane-grid.ts +250 -0
  382. package/src/surfaces/panel-activity.json +563 -0
  383. package/src/surfaces/panel-activity.ts +187 -0
  384. package/src/surfaces/panel-data.json +141 -0
  385. package/src/surfaces/panel-data.ts +156 -0
  386. package/src/surfaces/panel-deploy-checklist.json +283 -0
  387. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  388. package/src/surfaces/panel-elements.json +367 -0
  389. package/src/surfaces/panel-elements.ts +175 -0
  390. package/src/surfaces/panel-i18n.json +569 -0
  391. package/src/surfaces/panel-i18n.ts +212 -0
  392. package/src/surfaces/panel-imports.json +780 -0
  393. package/src/surfaces/panel-imports.ts +209 -0
  394. package/src/surfaces/panel-outline.json +734 -0
  395. package/src/surfaces/panel-outline.ts +326 -0
  396. package/src/surfaces/panel-page.json +1017 -0
  397. package/src/surfaces/panel-page.ts +240 -0
  398. package/src/surfaces/panel-problems.json +497 -0
  399. package/src/surfaces/panel-problems.ts +157 -0
  400. package/src/surfaces/panel-signals.json +1973 -0
  401. package/src/surfaces/panel-signals.ts +436 -0
  402. package/src/surfaces/panel-stylebook-layers.json +317 -0
  403. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  404. package/src/surfaces/preferences.json +850 -0
  405. package/src/surfaces/preferences.ts +332 -0
  406. package/src/surfaces/progress-modal.json +110 -0
  407. package/src/surfaces/progress-modal.ts +150 -0
  408. package/src/surfaces/properties-panel.json +1578 -0
  409. package/src/surfaces/properties-panel.ts +337 -0
  410. package/src/surfaces/publish.json +945 -0
  411. package/src/surfaces/publish.ts +392 -0
  412. package/src/surfaces/push-plan.json +110 -0
  413. package/src/surfaces/push-plan.ts +87 -0
  414. package/src/surfaces/rail.json +255 -0
  415. package/src/surfaces/rail.ts +206 -0
  416. package/src/surfaces/reference-field.json +191 -0
  417. package/src/surfaces/reference-field.ts +168 -0
  418. package/src/surfaces/schema-builder.json +1011 -0
  419. package/src/surfaces/schema-builder.ts +181 -0
  420. package/src/surfaces/schema-form.json +1013 -0
  421. package/src/surfaces/schema-form.ts +287 -0
  422. package/src/surfaces/secret-field.json +60 -0
  423. package/src/surfaces/secret-field.ts +146 -0
  424. package/src/surfaces/seo.json +932 -0
  425. package/src/surfaces/seo.ts +334 -0
  426. package/src/surfaces/settings-contexts.json +538 -0
  427. package/src/surfaces/settings-contexts.ts +196 -0
  428. package/src/surfaces/settings-contributed.json +489 -0
  429. package/src/surfaces/settings-contributed.ts +199 -0
  430. package/src/surfaces/settings-css-vars.json +820 -0
  431. package/src/surfaces/settings-css-vars.ts +199 -0
  432. package/src/surfaces/settings-defs.json +1363 -0
  433. package/src/surfaces/settings-defs.ts +232 -0
  434. package/src/surfaces/settings-deploy.json +108 -0
  435. package/src/surfaces/settings-deploy.ts +135 -0
  436. package/src/surfaces/settings-extensions.json +486 -0
  437. package/src/surfaces/settings-extensions.ts +201 -0
  438. package/src/surfaces/settings-head.json +779 -0
  439. package/src/surfaces/settings-head.ts +397 -0
  440. package/src/surfaces/settings-locales.json +420 -0
  441. package/src/surfaces/settings-locales.ts +137 -0
  442. package/src/surfaces/settings-overview.json +423 -0
  443. package/src/surfaces/settings-overview.ts +218 -0
  444. package/src/surfaces/settings-packages.json +549 -0
  445. package/src/surfaces/settings-packages.ts +158 -0
  446. package/src/surfaces/settings-pane.json +147 -0
  447. package/src/surfaces/settings-pane.ts +150 -0
  448. package/src/surfaces/settings-rawjson.json +104 -0
  449. package/src/surfaces/settings-rawjson.ts +107 -0
  450. package/src/surfaces/shell.json +99 -0
  451. package/src/surfaces/shell.ts +30 -0
  452. package/src/surfaces/slash-menu.json +180 -0
  453. package/src/surfaces/slash-menu.ts +272 -0
  454. package/src/surfaces/statements.json +607 -0
  455. package/src/surfaces/statements.ts +238 -0
  456. package/src/surfaces/statusbar.json +94 -0
  457. package/src/{panels → surfaces}/statusbar.ts +163 -90
  458. package/src/surfaces/style-panel.json +1643 -0
  459. package/src/surfaces/style-panel.ts +338 -0
  460. package/src/surfaces/stylebook-chrome.json +122 -0
  461. package/src/surfaces/stylebook-chrome.ts +122 -0
  462. package/src/surfaces/tab-strip.json +448 -0
  463. package/src/surfaces/tab-strip.ts +200 -0
  464. package/src/surfaces/target-line.json +419 -0
  465. package/src/surfaces/target-line.ts +349 -0
  466. package/src/surfaces/toasts.json +189 -0
  467. package/src/surfaces/welcome.json +571 -0
  468. package/src/surfaces/welcome.ts +338 -0
  469. package/src/tabs/project-config.ts +71 -15
  470. package/src/tabs/tab.ts +52 -1
  471. package/src/types.ts +22 -0
  472. package/src/ui/ai-credentials-form.ts +104 -100
  473. package/src/ui/ai-managed-connect.ts +54 -36
  474. package/src/ui/ai-model-picker.ts +75 -47
  475. package/src/ui/cf-account-picker.ts +76 -141
  476. package/src/ui/color-selector.ts +80 -301
  477. package/src/ui/dynamic-slot.ts +43 -283
  478. package/src/ui/expression-editor.ts +797 -576
  479. package/src/ui/field-input.ts +8 -181
  480. package/src/ui/form-controls.ts +838 -366
  481. package/src/ui/formula-chips.ts +80 -85
  482. package/src/ui/kit.ts +33 -0
  483. package/src/ui/layers.ts +293 -593
  484. package/src/ui/media-picker.ts +203 -284
  485. package/src/ui/panel-resize.ts +251 -64
  486. package/src/ui/popover-surface.ts +153 -0
  487. package/src/ui/progress-modal.ts +22 -60
  488. package/src/ui/regions.ts +13 -7
  489. package/src/ui/schema-form.ts +906 -440
  490. package/src/ui/surface.ts +122 -0
  491. package/src/ui/unit-selector.ts +15 -131
  492. package/src/ui/value-source.ts +14 -0
  493. package/src/ui/virtual-window.ts +88 -9
  494. package/src/utils/canvas-media.ts +72 -0
  495. package/src/utils/edit-display.ts +7 -2
  496. package/src/utils/element-selectors.ts +69 -0
  497. package/src/utils/link-target.ts +2 -2
  498. package/src/utils/studio-utils.ts +0 -10
  499. package/src/view.ts +15 -0
  500. package/src/workspace/pane-derive.ts +36 -14
  501. package/src/workspace/workspace.ts +15 -6
  502. package/styles/canvas.css +72 -467
  503. package/styles/forced-colors.css +48 -82
  504. package/styles/forced-colors.json +41 -0
  505. package/styles/inspector.css +2 -1301
  506. package/styles/overlays.css +96 -2823
  507. package/styles/panels.css +6 -1423
  508. package/styles/shell-frame.css +272 -0
  509. package/styles/shell-frame.json +227 -0
  510. package/styles/shell.css +0 -1568
  511. package/styles/tokens.css +65 -136
  512. package/styles/tokens.json +84 -0
  513. package/dist/chunks/Overlay.dev-etqjwyf9.js +0 -23
  514. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  515. package/dist/chunks/cf-account-picker-en86v7x7.js +0 -163
  516. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  517. package/dist/chunks/components-zmx10t62.js +0 -21
  518. package/dist/chunks/content-source-48xg86wj.js +0 -49
  519. package/dist/chunks/convert-to-repeater-43tfn7cs.js +0 -268
  520. package/dist/chunks/editor-cptq5jp1.js +0 -37
  521. package/dist/chunks/entry-commands-e63f1xc0.js +0 -46
  522. package/dist/chunks/extension-sections-txv08xxg.js +0 -311
  523. package/dist/chunks/file-ops-wbh4hhsx.js +0 -48
  524. package/dist/chunks/files-3kfkwhk4.js +0 -93
  525. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  526. package/dist/chunks/focus-trap.esm-9t2drp0g.js +0 -1025
  527. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  528. package/dist/chunks/format-host-w16q81tf.js +0 -43
  529. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  530. package/dist/chunks/git-panel-532whr1y.js +0 -59
  531. package/dist/chunks/index-zqxmqxmh.js +0 -109
  532. package/dist/chunks/jx-validate-8er6gbxy.js +0 -19
  533. package/dist/chunks/layers-panel-07hm7g5j.js +0 -67
  534. package/dist/chunks/layers-q75tj2mf.js +0 -45
  535. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  536. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  537. package/dist/chunks/notify-yjm79n4s.js +0 -30
  538. package/dist/chunks/parse-24d0gay3.js +0 -19
  539. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  540. package/dist/chunks/publish-panel-v9st96ja.js +0 -29
  541. package/dist/chunks/quick-search-zccjp6gv.js +0 -66
  542. package/dist/chunks/references-3qx8fkyp.js +0 -29
  543. package/dist/chunks/right-panel-vm3b6kwy.js +0 -46
  544. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  545. package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +0 -18
  546. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  547. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  548. package/dist/chunks/sp-tooltip.dev-4sastdnw.js +0 -15
  549. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  550. package/dist/chunks/studio-0a5qrh01.js +0 -3
  551. package/dist/chunks/studio-0bq6eh7v.js +0 -12
  552. package/dist/chunks/studio-18j3bmcz.js +0 -14
  553. package/dist/chunks/studio-1ngbejft.js +0 -181
  554. package/dist/chunks/studio-4b5z1x43.js +0 -424
  555. package/dist/chunks/studio-4n2b5gzb.js +0 -357
  556. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  557. package/dist/chunks/studio-5fx3g9jg.js +0 -4325
  558. package/dist/chunks/studio-5myknm0a.js +0 -1903
  559. package/dist/chunks/studio-7afd21nw.js +0 -67
  560. package/dist/chunks/studio-7nte2hj4.js +0 -613
  561. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  562. package/dist/chunks/studio-8q517dfr.js +0 -24
  563. package/dist/chunks/studio-950k0dx6.js +0 -6939
  564. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  565. package/dist/chunks/studio-a0tswy0w.js +0 -58
  566. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  567. package/dist/chunks/studio-cmb03bg5.js +0 -13890
  568. package/dist/chunks/studio-d1ks410h.js +0 -175
  569. package/dist/chunks/studio-ef49pnzx.js +0 -387
  570. package/dist/chunks/studio-eqq1w638.js +0 -113
  571. package/dist/chunks/studio-ew0djmhg.js +0 -341
  572. package/dist/chunks/studio-gfgb8pe6.js +0 -1652
  573. package/dist/chunks/studio-h4rxscfc.js +0 -10
  574. package/dist/chunks/studio-jc994dnr.js +0 -1066
  575. package/dist/chunks/studio-kyh9avvv.js +0 -28
  576. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  577. package/dist/chunks/studio-mtfnaqs9.js +0 -659
  578. package/dist/chunks/studio-n6j9t10q.js +0 -318
  579. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  580. package/dist/chunks/studio-qcy05dp8.js +0 -1743
  581. package/dist/chunks/studio-qq6jym04.js +0 -53
  582. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  583. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  584. package/dist/chunks/studio-t7qb9db8.js +0 -665
  585. package/dist/chunks/studio-tmc5emrw.js +0 -8
  586. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  587. package/dist/chunks/studio-zczps70q.js +0 -378
  588. package/dist/chunks/studio-zqazsct2.js +0 -1823
  589. package/dist/chunks/workspace-fjx52ryv.js +0 -89
  590. package/src/panels/activity-bar.ts +0 -251
  591. package/src/panels/panel-scheduler.ts +0 -219
  592. package/src/panels/style-inputs.ts +0 -237
  593. package/src/panels/target-line.ts +0 -274
  594. package/src/panels/welcome-screen.ts +0 -346
  595. package/src/ui/button-group.ts +0 -102
  596. package/src/ui/choice-field.ts +0 -72
  597. package/src/ui/field-row.ts +0 -249
  598. package/src/ui/formula-palette.ts +0 -213
  599. package/src/ui/icons.ts +0 -52
  600. package/src/ui/jx-theme.ts +0 -130
  601. package/src/ui/spectrum.ts +0 -340
  602. package/src/ui/value-selector.ts +0 -174
  603. package/src/ui/widgets.ts +0 -172
  604. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  605. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  606. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  607. /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
@@ -29,6 +29,14 @@ interface BuildSystemPromptOptions {
29
29
  * prompt-shape tests — advertises the same list it always did.
30
30
  */
31
31
  treeEditable?: boolean | undefined;
32
+ /**
33
+ * The blurbs of the tools projected from command records this round —
34
+ * `services/ai-command-tools.ts`'s `commandToolBlurbs(activeRegistry())`. Rendered after the hand
35
+ * tools under every "Tools available right now" heading, one line each. Passed in rather than
36
+ * read here so this stays a pure function of its options: a caller that passes none sees the hand
37
+ * list it always did, and only `document-assistant.ts`, which holds the registry, adds them.
38
+ */
39
+ commandTools?: readonly string[] | undefined;
32
40
  /**
33
41
  * Whether the platform can import a site. Defaults TRUE so this stays a pure function of what it
34
42
  * is given — a caller that knows nothing about the platform gets the full list, and only
@@ -37,11 +45,32 @@ interface BuildSystemPromptOptions {
37
45
  canImport?: boolean | undefined;
38
46
  /** Project-relative file paths for the inventory section (project modes; capped). */
39
47
  fileInventory?: string[] | undefined;
48
+ /**
49
+ * What this backend can run, enabled or not.
50
+ *
51
+ * Passed in rather than read here, because it comes from the PLATFORM and this builder is a pure
52
+ * function of its options. Without it the model can only discover an extension by being told
53
+ * about one, which is how a request for a blog gets a hand-built Markdown pipeline instead of
54
+ * `@jxsuite/parser`.
55
+ */
56
+ extensionCatalog?: readonly ExtensionCatalogSummary[] | undefined;
57
+ }
58
+
59
+ /** One extension this backend can run — the prompt's view of a catalogue entry. */
60
+ export interface ExtensionCatalogSummary {
61
+ name: string;
62
+ title?: string | undefined;
63
+ description?: string | undefined;
64
+ /** `project.json` keys that become legal once it is enabled. */
65
+ sections?: readonly string[] | undefined;
40
66
  }
41
67
 
42
68
  /** Max file paths embedded in the prompt's inventory section. */
43
69
  const FILE_INVENTORY_CAP = 100;
44
70
 
71
+ /** Max catalogue entries listed in the prompt. */
72
+ const EXTENSION_CATALOG_CAP = 20;
73
+
45
74
  // ─── Tool tiers (single source of truth for prompt AND gating) ──────────────
46
75
 
47
76
  /** Studio state a tool tier requires. Used by the gating registry AND the prompt tool list. */
@@ -54,9 +83,14 @@ const FILE_INVENTORY_CAP = 100;
54
83
  * with Project Settings open, `project.json` drawn as a layer tree. The assistant's tier asked only
55
84
  * whether a tab existed, so in that exact state the agent was advertised `remove_node` and
56
85
  * `move_node` and executed them against the file that defines the project, while the human's
57
- * `delete_node` was refused. `remove_node` self-refuses only the document root (`path.length < 2`),
86
+ * `delete_node` was refused. `remove_node` self-refused only the document root (`path.length < 2`),
58
87
  * a weaker test than `structurallyEditable`, so a repeater template or `$switch` case was removable
59
- * by the agent and not by the person.
88
+ * by the agent and not by the person. A tier was the first fix; the second predicate went with
89
+ * `remove_node` itself, which is now `delete_node`, the projection of `selection.delete`
90
+ * (`services/ai-command-tools.ts`) — one record, one gate, and no tier row here at all.
91
+ *
92
+ * This union is the HAND table's vocabulary and nothing a record declares: a projected command's
93
+ * tier is derived from its `level` by the bridge.
60
94
  */
61
95
  export type AiToolTier = "always" | "no-project" | "project" | "document" | "document-tree";
62
96
 
@@ -76,9 +110,15 @@ export interface AiToolInfo {
76
110
  }
77
111
 
78
112
  /**
79
- * Every assistant tool with its availability tier and prompt blurb. document-assistant.ts derives
80
- * the gating predicates from the same rows, so the advertised tool list and the executable tool
81
- * list cannot drift (a test asserts the names match the registered tools).
113
+ * Every HAND-REGISTERED assistant tool with its availability tier and prompt blurb.
114
+ * document-assistant.ts derives the gating predicates from the same rows, so the advertised tool
115
+ * list and the executable tool list cannot drift (a test asserts the names match the registered
116
+ * tools, and that none is also a command record's projection).
117
+ *
118
+ * The other kind of tool is not here and must not be added here: a command record that declares
119
+ * `aiTool` is projected by `services/ai-command-tools.ts`, gated by the record's own `when` /
120
+ * `enablement`, and described by the record. `enable_extension`, `disable_extension` and
121
+ * `delete_node` (né `remove_node`) left this table for that one.
82
122
  */
83
123
  export const AI_TOOL_TIERS: AiToolInfo[] = [
84
124
  // Always — a question is not gated on what happens to be open
@@ -181,11 +221,6 @@ export const AI_TOOL_TIERS: AiToolInfo[] = [
181
221
  blurb:
182
222
  "add_child(parentPath, index, node) — insert a new node into the children of parentPath at index.",
183
223
  },
184
- {
185
- name: "remove_node",
186
- tier: "document-tree",
187
- blurb: "remove_node(path) — remove the node at path.",
188
- },
189
224
  {
190
225
  name: "move_node",
191
226
  tier: "document-tree",
@@ -644,17 +679,24 @@ export function buildSystemPrompt({
644
679
  hasProject = Boolean(projectRoot),
645
680
  treeEditable = true,
646
681
  canImport = true,
682
+ commandTools = [],
647
683
  fileInventory,
684
+ extensionCatalog,
648
685
  }: BuildSystemPromptOptions = {}) {
649
686
  const hasDocument = Boolean(document);
650
687
 
651
688
  // 1. Role, state-appropriate workflow, and the tool list for the current state.
652
689
  // The list the model is TOLD about and the list the gate will honour are the same filter, so a
653
- // Refusal is never a surprise to it.
654
- const toolList = AI_TOOL_TIERS.filter((t) =>
655
- toolActive(t, { canImport, hasDocument, hasProject, treeEditable }),
656
- )
657
- .map((t) => `- ${t.blurb}`)
690
+ // Refusal is never a surprise to it. The command-projected tools arrive already filtered by
691
+ // Their records' own gates, for the same reason — one function answers both the prompt and the
692
+ // Executor (`advertisedCommandTools`).
693
+ const toolList = [
694
+ ...AI_TOOL_TIERS.filter((t) =>
695
+ toolActive(t, { canImport, hasDocument, hasProject, treeEditable }),
696
+ ).map((t) => t.blurb),
697
+ ...commandTools,
698
+ ]
699
+ .map((blurb) => `- ${blurb}`)
658
700
  .join("\n");
659
701
 
660
702
  const role = `You are an expert Jx builder assistant embedded in Jx Studio. You help users build websites, components, pages, and layouts using the Jx JSON schema. The live jxsuite.com marketing site is built entirely with Jx — you can produce production-quality Jx code.`;
@@ -722,7 +764,12 @@ Be concise. Don't explain what Jx is unless asked. Just build.`;
722
764
 
723
765
  // 6. Project context
724
766
  if (hasProject && (projectConfig || components || projectRoot)) {
725
- const projectSummary = buildProjectSummary({ projectConfig, components, projectRoot });
767
+ const projectSummary = buildProjectSummary({
768
+ components,
769
+ extensionCatalog,
770
+ projectConfig,
771
+ projectRoot,
772
+ });
726
773
  if (projectSummary) {
727
774
  sections.push(`## Project Context\n\n${projectSummary}`);
728
775
  }
@@ -744,7 +791,7 @@ Be concise. Don't explain what Jx is unless asked. Just build.`;
744
791
  If a tool call fails (returns { success: false }):
745
792
  1. Read the error message carefully — it includes a "→ Fix:" hint telling you exactly how to correct the error.
746
793
  2. Each error points to a specific path in the document and a specific rule violation.
747
- 3. Apply the suggested fix using set_property, remove_node, or add_child as appropriate.
794
+ 3. Apply the suggested fix using set_property, delete_node, or add_child as appropriate.
748
795
  4. Do NOT re-issue the exact same tool call with the same arguments — you must CHANGE something.
749
796
  5. If you see the SAME error after 2 attempts, try a completely different approach (e.g., remove and re-add the node instead of patching it).
750
797
 
@@ -762,7 +809,7 @@ If a tool call fails (returns { success: false }):
762
809
 
763
810
  ### If you keep getting errors:
764
811
  - Call read_document again — the document may have changed since you last read it.
765
- - Remove the problematic node entirely with remove_node, then re-create it correctly with add_child.
812
+ - Remove the problematic node entirely with delete_node, then re-create it correctly with add_child.
766
813
  - If the error message points to a different path than you expected, the node might have moved due to previous edits.`);
767
814
 
768
815
  return sections.join("\n\n---\n\n");
@@ -841,6 +888,7 @@ function buildProjectSummary({
841
888
  projectConfig,
842
889
  components,
843
890
  projectRoot,
891
+ extensionCatalog,
844
892
  }: Omit<BuildSystemPromptOptions, "document">) {
845
893
  const lines: string[] = [];
846
894
 
@@ -852,6 +900,13 @@ function buildProjectSummary({
852
900
  lines.push(`Root: ${projectRoot}`);
853
901
  }
854
902
 
903
+ /* One line, closing a gap that was pure oversight: this function has always received the whole
904
+ `projectConfig`, `extensions` included, and dropped it on the floor. */
905
+ const enabled = projectConfig?.extensions ?? [];
906
+ if (enabled.length > 0) {
907
+ lines.push(`Extensions enabled: ${enabled.join(", ")}`);
908
+ }
909
+
855
910
  // Available components — tag + purpose so the model can reuse them
856
911
  if (components && components.length > 0) {
857
912
  lines.push(`Available components (reuse these instead of rebuilding):`);
@@ -898,6 +953,43 @@ function buildProjectSummary({
898
953
  }
899
954
  }
900
955
 
956
+ /*
957
+ * The catalogue, last, so the design-token block keeps its prominence. The guidance names
958
+ * CAPABILITIES rather than packages on purpose: the capability-to-package mapping is what each
959
+ * entry's own description is for, and hardcoding "@jxsuite/parser" here would be a second,
960
+ * staler copy of the backend's answer.
961
+ */
962
+ if (extensionCatalog && extensionCatalog.length > 0) {
963
+ const enabledSet = new Set(enabled);
964
+ lines.push(
965
+ `Extensions available. Turn one on with enable_extension BEFORE writing the project.json ` +
966
+ `section it owns: a section belonging to a disabled extension is a schema error, and an ` +
967
+ `"extensions" entry whose package is not installed fails the build. When a request needs ` +
968
+ `a capability the core does not have (a blog or any folder of Markdown, a search box, a ` +
969
+ `feed, sign-ins, a database table), look for it below rather than hand-building it.`,
970
+ );
971
+ for (const entry of extensionCatalog.slice(0, EXTENSION_CATALOG_CAP)) {
972
+ const parts = [` ${entry.name}`];
973
+ if (entry.title) {
974
+ parts.push(` — ${entry.title}.`);
975
+ }
976
+ if (entry.description) {
977
+ parts.push(` ${entry.description}`);
978
+ }
979
+ if (entry.sections && entry.sections.length > 0) {
980
+ parts.push(` Contributes: ${entry.sections.join(", ")}.`);
981
+ }
982
+ if (enabledSet.has(entry.name)) {
983
+ parts.push(" [enabled]");
984
+ }
985
+ lines.push(parts.join(""));
986
+ }
987
+ if (extensionCatalog.length > EXTENSION_CATALOG_CAP) {
988
+ const more = extensionCatalog.length - EXTENSION_CATALOG_CAP;
989
+ lines.push(` … and ${more} more (open_settings { section: "extensions" })`);
990
+ }
991
+ }
992
+
901
993
  // Breakpoints — surfaced prominently so the model uses @--breakpoint responsive overrides
902
994
  if (projectConfig?.$media) {
903
995
  const breakpoints = Object.entries(projectConfig.$media)
@@ -12,7 +12,6 @@ import { createToolDefinition } from "@jxsuite/ai/tools";
12
12
  import type { ToolRegistry, ToolResult } from "@jxsuite/ai/tools";
13
13
  import type { JxMutableNode, JxPath, JxStateDefinition } from "@jxsuite/schema/types";
14
14
  import { getNodeAtPath } from "../state";
15
- import { toRaw } from "../reactivity";
16
15
  import type { Tab } from "../tabs/tab";
17
16
  import {
18
17
  beginBatch,
@@ -20,7 +19,6 @@ import {
20
19
  isBatching,
21
20
  mutateInsertNode,
22
21
  mutateMoveNode,
23
- mutateRemoveNode,
24
22
  mutateUpdateProperty,
25
23
  mutateUpdateStyle,
26
24
  transactDoc,
@@ -28,7 +26,18 @@ import {
28
26
  import type { JxNodeValue } from "../tabs/transact";
29
27
  import { validateDoc } from "./jx-validate";
30
28
  import { recordWrite } from "./ai-writes";
31
- import { flagHardcodedTokens, formatTokenHints } from "./token-lint";
29
+ import { serializeJson } from "../files/json-layout";
30
+ import {
31
+ reportDocumentWrite,
32
+ snapshotBeforeWrite,
33
+ translateValidationError,
34
+ } from "./ai-write-report";
35
+ import type { RenderVerdict } from "./ai-write-report";
36
+
37
+ /* Re-exported from its new home so `ai-project-tools.ts` and the tests keep their import: the
38
+ translation moved with the verdict it belongs to (`ai-write-report.ts`), where every document
39
+ write — hand-registered or projected from a command record — now reads it. */
40
+ export { translateValidationError } from "./ai-write-report";
32
41
 
33
42
  const PATH_DESCRIPTION =
34
43
  "Path to a node in the document, as a JSON array of keys/indices from the root " +
@@ -45,74 +54,17 @@ function noDocError(): ToolResult {
45
54
  }
46
55
 
47
56
  /**
48
- * Translate a raw JSON Schema validation error into a Jx-specific actionable message. The LLM needs
49
- * concrete guidance on HOW to fix errors, not just what rule was violated. Shared with the
50
- * project-level file tools (ai-project-tools.ts), which pre-validate Jx documents before writing.
51
- *
52
- * @param {string} rawError - Message from ajv (e.g. "/children/0/style: must NOT have additional
53
- * property")
54
- * @returns {string}
55
- */
56
- export function translateValidationError(rawError: string): string {
57
- const lower = rawError.toLowerCase();
58
-
59
- // Additional property — extract the offending key from the message if present
60
- if (
61
- lower.includes("must not have additional property") ||
62
- lower.includes("additional properties")
63
- ) {
64
- 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": "..." } }.`;
65
- }
66
-
67
- // Pattern — usually tagName hyphen rule
68
- if (lower.includes("must match pattern")) {
69
- 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").`;
70
- }
71
-
72
- // Type error
73
- if (lower.includes("must be string")) {
74
- return `${rawError}\n → Fix: Wrap the value in quotes — all Jx property values should be strings. For example, use "10px" (string) not 10px (unquoted).`;
75
- }
76
-
77
- if (lower.includes("must be number") || lower.includes("must be integer")) {
78
- return `${rawError}\n → Fix: Remove quotes from the numeric value — it should be a plain number, not a string.`;
79
- }
80
-
81
- if (lower.includes("must be object") || lower.includes("must be array")) {
82
- return `${rawError}\n → Fix: The value must be an object/array (use {} or []), not a string or number.`;
83
- }
84
-
85
- if (lower.includes("must be boolean")) {
86
- return `${rawError}\n → Fix: Use true or false without quotes for boolean values.`;
87
- }
88
-
89
- // Required property
90
- if (lower.includes("must have required property")) {
91
- return `${rawError}\n → Fix: Add the missing required property. Every Jx element must have at least a "tagName" field.`;
92
- }
93
-
94
- // Enum / allowed values
95
- if (lower.includes("must be equal to one of the allowed values")) {
96
- return `${rawError}\n → Fix: Change the value to one of the allowed options listed in the error.`;
97
- }
98
-
99
- return rawError;
100
- }
101
-
102
- /**
103
- * Apply a mutation, then validate the document and report only the schema errors the edit newly
104
- * introduced (the eval signal — ADR §6b). The change stays applied either way (optimistic apply +
105
- * undo, ADR §5); reporting the errors lets the agent loop self-correct on the next round.
106
- *
107
- * When a renderCheck function is provided, a second gate runs after schema validation passes: the
108
- * mutated document is rendered in a detached DOM context and any render-time throws are surfaced as
109
- * tool errors (same contract as schema errors).
57
+ * Apply a mutation, then hand the verdict to `ai-write-report.ts`: only the schema errors the edit
58
+ * NEWLY introduced are reported (the eval signal — ADR §6b), the render check runs when a
59
+ * renderCheck was provided and rendering worked before, and a success carries the token hints. The
60
+ * change stays applied either way (optimistic apply + undo, ADR §5); reporting the errors lets the
61
+ * agent loop self-correct on the next round.
110
62
  *
111
63
  * @param {import("../tabs/tab").Tab} tab
112
64
  * @param {(t: import("../tabs/tab").Tab) => void} mutationFn
113
65
  * @param {string} summary
114
66
  * @param {(doc: unknown) => Promise<string[]>} validate
115
- * @param {((doc: unknown) => Promise<{ ok: true } | { ok: false; error: string }>) | undefined} renderCheck
67
+ * @param {((doc: unknown) => Promise<RenderVerdict>) | undefined} renderCheck
116
68
  * @param {Record<string, string> | undefined} projectStyle
117
69
  * @returns {Promise<import("@jxsuite/ai/tools").ToolResult>}
118
70
  */
@@ -121,12 +73,11 @@ async function applyAndValidate(
121
73
  mutationFn: (t: Tab) => void,
122
74
  summary: string,
123
75
  validate: (doc: unknown) => Promise<string[]>,
124
- renderCheck: ((doc: unknown) => Promise<{ ok: true } | { ok: false; error: string }>) | undefined,
76
+ renderCheck: ((doc: unknown) => Promise<RenderVerdict>) | undefined,
125
77
  projectStyle: Record<string, string> | undefined,
126
78
  ): Promise<ToolResult> {
127
- const rawBefore = toRaw(tab.doc.document);
128
- const before = new Set(await validate(rawBefore));
129
- const renderOkBefore = renderCheck ? await renderCheck(rawBefore) : { ok: true };
79
+ const deps = { getProjectStyle: () => projectStyle, renderCheck, validate };
80
+ const before = await snapshotBeforeWrite(tab, deps);
130
81
 
131
82
  /* AND THE WRITE CAN BE REFUSED, in which case the model must be told rather than congratulated.
132
83
  The collab gate pauses structural editing while source is canonical, and this went on to
@@ -147,37 +98,7 @@ async function applyAndValidate(
147
98
  went through transactDoc, so the tab's history — and "Restore to here" — can reach it. */
148
99
  recordWrite({ disk: false, ok: true, path: tab.documentPath ?? "(untitled)", tool: summary });
149
100
 
150
- const rawAfter = toRaw(tab.doc.document);
151
- const after = await validate(rawAfter);
152
- const newErrors = after.filter((e) => !before.has(e));
153
- if (newErrors.length > 0) {
154
- const formatted = newErrors.map((e) => `- ${translateValidationError(e)}`).join("\n");
155
- return {
156
- success: false,
157
- error: `Change applied, but it introduced schema errors. Fix these issues with follow-up edits:\n${formatted}`,
158
- };
159
- }
160
-
161
- if (renderCheck && renderOkBefore.ok) {
162
- const renderResult = await renderCheck(rawAfter);
163
- if (!renderResult.ok) {
164
- return {
165
- success: false,
166
- error: `Change applied and schema-valid, but it broke rendering. Fix with follow-up edits:\n- ${renderResult.error}`,
167
- };
168
- }
169
- }
170
-
171
- // Soft token-discipline hints (never fail the mutation)
172
- if (projectStyle) {
173
- const findings = flagHardcodedTokens(rawAfter, projectStyle);
174
- const hints = formatTokenHints(findings);
175
- if (hints) {
176
- return { success: true, summary: `${summary}\n\n${hints}` };
177
- }
178
- }
179
-
180
- return { success: true, summary };
101
+ return reportDocumentWrite(tab, before, summary, deps);
181
102
  }
182
103
 
183
104
  /**
@@ -258,7 +179,7 @@ export function registerAiTools(
258
179
  name: "read_document",
259
180
  description:
260
181
  "Read the current Jx document, or the subtree at a given path. Use this to discover " +
261
- "node paths before calling set_property, add_child, or remove_node.",
182
+ "node paths before calling set_property, add_child, or delete_node.",
262
183
  parameters: {
263
184
  type: "object",
264
185
  properties: {
@@ -751,7 +672,9 @@ export function registerAiTools(
751
672
  }
752
673
  }
753
674
  try {
754
- await saveFile(relPath, JSON.stringify(content, null, 2));
675
+ // The save serializer, layout-less (`files/json-layout.ts`): the assistant supplied a
676
+ // Value, not a text, so the formatter's layout for fresh output is the right one.
677
+ await saveFile(relPath, serializeJson(content, null));
755
678
  recordWrite({ disk: true, ok: true, path: relPath, tool: "create_component" });
756
679
  return {
757
680
  success: true,
@@ -828,7 +751,8 @@ export function registerAiTools(
828
751
  }
829
752
  }
830
753
  try {
831
- await saveFile(relPath, JSON.stringify(content, null, 2));
754
+ // As `create_component`: a value the assistant supplied, written in the formatter's layout.
755
+ await saveFile(relPath, serializeJson(content, null));
832
756
  recordWrite({ disk: true, ok: true, path: relPath, tool: "create_page" });
833
757
  return {
834
758
  success: true,
@@ -915,43 +839,4 @@ export function registerAiTools(
915
839
  },
916
840
  }),
917
841
  );
918
-
919
- registry.register(
920
- createToolDefinition({
921
- name: "remove_node",
922
- description: "Remove the node at the given path from its parent's children array.",
923
- parameters: {
924
- type: "object",
925
- properties: {
926
- path: {
927
- type: "array",
928
- description: `${PATH_DESCRIPTION} Cannot be the document root.`,
929
- items: { type: ["string", "number"] },
930
- },
931
- },
932
- required: ["path"],
933
- },
934
- async execute(args) {
935
- const tab = getTab();
936
- if (!tab) {
937
- return noDocError();
938
- }
939
- const { path } = args as { path: JxPath };
940
- if (path.length < 2) {
941
- return { success: false, error: "Cannot remove the document root." };
942
- }
943
- if (getNodeAtPath(tab.doc.document, path) === undefined) {
944
- return { success: false, error: `No node exists at path ${JSON.stringify(path)}.` };
945
- }
946
- return applyAndValidate(
947
- tab,
948
- (t) => mutateRemoveNode(t, path),
949
- `Removed node at ${JSON.stringify(path)}.`,
950
- validate,
951
- renderCheck,
952
- styleOf(),
953
- );
954
- },
955
- }),
956
- );
957
842
  }
@@ -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
+ }