@jxsuite/studio 4.0.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 (613) 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-xp8vnwma.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-nj44jpzj.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-rws7k4br.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-hbtp0eh1.js → studio-25hkdrkw.js} +356 -85
  62. package/dist/chunks/studio-26d7myd1.js +258 -0
  63. package/dist/chunks/{studio-p8j86wag.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/studio-3gxv60tn.js +422 -0
  65. package/dist/chunks/{studio-8swrjbny.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-gv8vvshc.js → studio-5523bpzt.js} +11 -11
  69. package/dist/chunks/{studio-5q69gfag.js → studio-57mf66w2.js} +1753 -2484
  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-eenfkt4e.js → studio-79y5sz51.js} +52 -38
  78. package/dist/chunks/{studio-4q0wznzf.js → studio-7e11jpa9.js} +461 -145
  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-arfpe389.js +195 -0
  88. package/dist/chunks/{studio-2zkz8evn.js → studio-az3zd49t.js} +473 -281
  89. package/dist/chunks/studio-cpvb2ed1.js +1171 -0
  90. package/dist/chunks/{studio-9r6j5ev1.js → studio-d0300636.js} +5078 -19
  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-4pqqxbrt.js → studio-em9nw8eh.js} +301 -112
  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-hhvs4sdg.js +195 -0
  100. package/dist/chunks/{studio-68n67094.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-kjjsjak4.js → studio-rkstz940.js} +3661 -6136
  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-yxrkyv8a.js → studio-s6z853aq.js} +12108 -11766
  113. package/dist/chunks/{studio-sf7zjgv1.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-htsf0w6m.js → studio-vz68yn9e.js} +31 -154
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/{studio-eesa1myv.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 +1812 -698
  135. package/dist/manifest.json +7 -0
  136. package/dist/studio.js +52900 -36573
  137. package/dist/workers/editor.worker.js +1040 -1085
  138. package/dist/workers/json.worker.js +1946 -1991
  139. package/dist/workers/ts.worker.js +4960 -5005
  140. package/favicon.ico +0 -0
  141. package/index.html +2 -0
  142. package/package.json +22 -55
  143. package/src/about/about-modal.ts +73 -123
  144. package/src/browse/library-commands.ts +20 -49
  145. package/src/browse/library-layouts.ts +87 -218
  146. package/src/browse/library-pane.ts +406 -438
  147. package/src/canvas/canvas-helpers.ts +0 -49
  148. package/src/canvas/canvas-live-render.ts +25 -2
  149. package/src/canvas/canvas-render.ts +666 -231
  150. package/src/canvas/canvas-surface.ts +0 -1
  151. package/src/canvas/canvas-utils.ts +310 -117
  152. package/src/canvas/dialog-path.ts +76 -0
  153. package/src/canvas/dialog-state.ts +67 -0
  154. package/src/canvas/diff-marks.ts +252 -0
  155. package/src/canvas/diff-toolbar.ts +349 -0
  156. package/src/canvas/diff-view.ts +123 -0
  157. package/src/canvas/edit-width-drag.ts +187 -0
  158. package/src/canvas/edit-width.ts +150 -0
  159. package/src/canvas/iframe-entry.ts +125 -8
  160. package/src/canvas/iframe-host.ts +271 -15
  161. package/src/canvas/iframe-interaction.ts +133 -13
  162. package/src/canvas/iframe-patch.ts +7 -1
  163. package/src/canvas/iframe-position.ts +5 -6
  164. package/src/canvas/iframe-protocol.ts +106 -5
  165. package/src/canvas/iframe-render.ts +373 -5
  166. package/src/canvas/iframe-slash.ts +2 -2
  167. package/src/canvas/iframe-subtree.ts +5 -8
  168. package/src/canvas/path-mapping.ts +25 -3
  169. package/src/canvas/popover-path.ts +106 -0
  170. package/src/canvas/popover-state.ts +155 -0
  171. package/src/canvas/surface-registry.ts +21 -10
  172. package/src/collab/presence-chips.ts +51 -73
  173. package/src/commands/app-commands.ts +10 -0
  174. package/src/commands/budget.ts +12 -0
  175. package/src/commands/command-args.ts +369 -6
  176. package/src/commands/defaults.ts +44 -14
  177. package/src/commands/live-context.ts +11 -5
  178. package/src/commands/reference.ts +12 -2
  179. package/src/commands/registry.ts +165 -8
  180. package/src/content/entry-commands.ts +16 -23
  181. package/src/content/entry-editor.ts +144 -101
  182. package/src/editor/canvas-slash-bridge.ts +2 -2
  183. package/src/editor/context-menu.ts +49 -200
  184. package/src/editor/convert-to-component.ts +42 -82
  185. package/src/editor/convert-to-repeater.ts +132 -173
  186. package/src/editor/inline-edit.ts +11 -0
  187. package/src/editor/shortcuts.ts +65 -26
  188. package/src/editor/slash-menu.ts +150 -157
  189. package/src/files/file-ops.ts +117 -11
  190. package/src/files/files.ts +949 -664
  191. package/src/files/json-layout.ts +474 -0
  192. package/src/files/media-paths.ts +13 -42
  193. package/src/files/media-usage.ts +41 -131
  194. package/src/files/serialize-document.ts +8 -1
  195. package/src/format/convert-file.ts +16 -10
  196. package/src/format/format-host.ts +50 -1
  197. package/src/github/github-auth.ts +71 -29
  198. package/src/github/github-publish.ts +57 -65
  199. package/src/grid/cell-editors.ts +46 -4
  200. package/src/grid/cell-popovers.ts +65 -62
  201. package/src/grid/grid-open.ts +86 -64
  202. package/src/grid/grid-panel.ts +390 -469
  203. package/src/grid/redirects-grid.ts +40 -44
  204. package/src/hosting/document.ts +2 -0
  205. package/src/hosting/layout.ts +10 -0
  206. package/src/i18n/i18n-commands.ts +127 -62
  207. package/src/media/media-pane.ts +83 -133
  208. package/src/new-project/add-repo-modal.ts +125 -176
  209. package/src/new-project/import-tab.ts +201 -250
  210. package/src/new-project/location-fields.ts +101 -165
  211. package/src/new-project/new-project-modal.ts +376 -367
  212. package/src/packages/jxsuite-update.ts +76 -18
  213. package/src/panels/activity-panel.ts +137 -104
  214. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  215. package/src/panels/ai-chat/chat-view.ts +307 -472
  216. package/src/panels/ai-chat/composer.ts +175 -153
  217. package/src/panels/ai-chat/sessions-view.ts +31 -62
  218. package/src/panels/ai-panel.ts +210 -185
  219. package/src/panels/block-action-bar.ts +437 -643
  220. package/src/panels/bottom-dock.ts +112 -47
  221. package/src/panels/chat-panel.ts +19 -14
  222. package/src/panels/data-explorer.ts +141 -102
  223. package/src/panels/data-grid.ts +183 -150
  224. package/src/panels/dnd.ts +75 -20
  225. package/src/panels/editors.ts +26 -19
  226. package/src/panels/elements-panel.ts +243 -186
  227. package/src/panels/empty-state.ts +26 -42
  228. package/src/panels/events-panel.ts +950 -729
  229. package/src/panels/formula-workspace.ts +434 -207
  230. package/src/panels/frontmatter-fields.ts +185 -153
  231. package/src/panels/frontmatter-panel.ts +411 -187
  232. package/src/panels/git-diff-open.ts +148 -0
  233. package/src/panels/git-panel.ts +679 -605
  234. package/src/panels/head-panel.ts +617 -435
  235. package/src/panels/i18n-panel.ts +153 -133
  236. package/src/panels/imports-panel.ts +388 -414
  237. package/src/panels/jump-bar.ts +174 -147
  238. package/src/panels/layers-panel.ts +785 -671
  239. package/src/panels/left-panel.ts +166 -94
  240. package/src/panels/navigator-panels.ts +1 -1
  241. package/src/panels/pane-context.ts +529 -677
  242. package/src/panels/pane-grid.ts +265 -241
  243. package/src/panels/panel-registry.ts +15 -4
  244. package/src/panels/problems-panel.ts +177 -99
  245. package/src/panels/properties-panel.ts +1525 -966
  246. package/src/panels/provenance.ts +31 -113
  247. package/src/panels/quick-search.ts +217 -172
  248. package/src/panels/right-panel.ts +135 -169
  249. package/src/panels/seo-modal.ts +346 -167
  250. package/src/panels/settings-menu.ts +109 -646
  251. package/src/panels/settings-pane.ts +102 -86
  252. package/src/panels/signals-panel.ts +1318 -1172
  253. package/src/panels/statement-editor.ts +556 -428
  254. package/src/panels/style-panel.ts +1367 -630
  255. package/src/panels/style-utils.ts +36 -32
  256. package/src/panels/stylebook-doc.ts +30 -73
  257. package/src/panels/stylebook-layers-panel.ts +202 -109
  258. package/src/panels/stylebook-panel.ts +124 -88
  259. package/src/panels/tab-strip.ts +385 -287
  260. package/src/platforms/cloud.ts +347 -86
  261. package/src/platforms/devserver.ts +13 -0
  262. package/src/publish/deploy-checklist.ts +124 -78
  263. package/src/publish/publish-commands.ts +4 -12
  264. package/src/publish/publish-panel.ts +165 -299
  265. package/src/services/a11y-report.ts +100 -43
  266. package/src/services/ai-command-tools.ts +468 -0
  267. package/src/services/ai-import-tools.ts +50 -12
  268. package/src/services/ai-models.ts +108 -1
  269. package/src/services/ai-session-store.ts +6 -0
  270. package/src/services/ai-system-prompt.ts +110 -18
  271. package/src/services/ai-tools.ts +28 -143
  272. package/src/services/ai-write-report.ts +174 -0
  273. package/src/services/context-manager.ts +12 -1
  274. package/src/services/document-assistant.ts +50 -2
  275. package/src/services/idle.ts +16 -14
  276. package/src/services/live-surfaces.ts +237 -0
  277. package/src/services/model-uri.ts +75 -0
  278. package/src/services/notify.ts +63 -6
  279. package/src/services/popover-report.ts +325 -0
  280. package/src/services/surface-registry.ts +56 -0
  281. package/src/services/tool-executor.ts +17 -0
  282. package/src/settings/contexts-section.ts +301 -299
  283. package/src/settings/contributed-section.ts +361 -222
  284. package/src/settings/css-vars-editor.ts +320 -325
  285. package/src/settings/defs-editor.ts +572 -535
  286. package/src/settings/dependencies-editor.ts +79 -107
  287. package/src/settings/extension-commands.ts +379 -0
  288. package/src/settings/extension-rows.ts +113 -0
  289. package/src/settings/extensions-section.ts +287 -0
  290. package/src/settings/general-settings.ts +130 -181
  291. package/src/settings/head-editor.ts +10 -305
  292. package/src/settings/locales-section.ts +146 -196
  293. package/src/settings/preferences-accounts.ts +193 -12
  294. package/src/settings/preferences-dialog.ts +384 -307
  295. package/src/settings/project-sections.ts +108 -181
  296. package/src/settings/schema-field-ui.ts +11 -399
  297. package/src/settings/section-registry.ts +8 -1
  298. package/src/settings/settings-document.ts +31 -29
  299. package/src/shell/tree.ts +42 -87
  300. package/src/shell.ts +48 -36
  301. package/src/studio.ts +90 -67
  302. package/src/style/token-ref.ts +0 -39
  303. package/src/surfaces/about.json +263 -0
  304. package/src/surfaces/about.ts +163 -0
  305. package/src/surfaces/add-repo.json +486 -0
  306. package/src/surfaces/add-repo.ts +236 -0
  307. package/src/surfaces/ai-chat.json +2185 -0
  308. package/src/surfaces/ai-chat.ts +549 -0
  309. package/src/surfaces/ai-credentials-form.json +332 -0
  310. package/src/surfaces/ai-credentials-form.ts +151 -0
  311. package/src/surfaces/ai-managed-connect.json +108 -0
  312. package/src/surfaces/ai-managed-connect.ts +123 -0
  313. package/src/surfaces/ai-model-picker.json +114 -0
  314. package/src/surfaces/ai-model-picker.ts +139 -0
  315. package/src/surfaces/block-action-bar.json +640 -0
  316. package/src/surfaces/block-action-bar.ts +368 -0
  317. package/src/surfaces/bottom-dock.json +154 -0
  318. package/src/surfaces/bottom-dock.ts +125 -0
  319. package/src/surfaces/canvas-stage.json +444 -0
  320. package/src/surfaces/canvas-stage.ts +253 -0
  321. package/src/surfaces/cf-account-picker.json +300 -0
  322. package/src/surfaces/cf-account-picker.ts +214 -0
  323. package/src/surfaces/commandbar.json +984 -0
  324. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
  325. package/src/surfaces/convert-repeater.json +309 -0
  326. package/src/surfaces/convert-repeater.ts +276 -0
  327. package/src/surfaces/data-actions.json +157 -0
  328. package/src/surfaces/data-actions.ts +115 -0
  329. package/src/surfaces/dialog.json +289 -0
  330. package/src/surfaces/dialog.ts +343 -0
  331. package/src/surfaces/diff-toolbar.json +266 -0
  332. package/src/surfaces/diff-toolbar.ts +139 -0
  333. package/src/surfaces/doc-header.json +739 -0
  334. package/src/surfaces/doc-header.ts +223 -0
  335. package/src/surfaces/empty-state.json +152 -0
  336. package/src/surfaces/empty-state.ts +173 -0
  337. package/src/surfaces/entry-editor.json +281 -0
  338. package/src/surfaces/entry-editor.ts +191 -0
  339. package/src/surfaces/expression-editor.json +977 -0
  340. package/src/surfaces/expression-editor.ts +266 -0
  341. package/src/surfaces/files-panel.json +592 -0
  342. package/src/surfaces/files-panel.ts +301 -0
  343. package/src/surfaces/formula-palette.json +364 -0
  344. package/src/surfaces/formula-palette.ts +340 -0
  345. package/src/surfaces/git-panel.json +1822 -0
  346. package/src/surfaces/git-panel.ts +272 -0
  347. package/src/surfaces/github-auth.json +112 -0
  348. package/src/surfaces/github-auth.ts +139 -0
  349. package/src/surfaces/github-publish.json +206 -0
  350. package/src/surfaces/github-publish.ts +169 -0
  351. package/src/surfaces/grid-cell.json +218 -0
  352. package/src/surfaces/grid-cell.ts +120 -0
  353. package/src/surfaces/grid-open.json +147 -0
  354. package/src/surfaces/grid-open.ts +87 -0
  355. package/src/surfaces/grid-panel.json +706 -0
  356. package/src/surfaces/grid-panel.ts +206 -0
  357. package/src/surfaces/grid-replace.json +179 -0
  358. package/src/surfaces/grid-replace.ts +89 -0
  359. package/src/surfaces/grid-views.json +446 -0
  360. package/src/surfaces/grid-views.ts +172 -0
  361. package/src/surfaces/inspector-dock.json +187 -0
  362. package/src/surfaces/inspector-dock.ts +161 -0
  363. package/src/surfaces/jump-bar.json +243 -0
  364. package/src/surfaces/jump-bar.ts +129 -0
  365. package/src/surfaces/jxsuite-update.json +146 -0
  366. package/src/surfaces/jxsuite-update.ts +149 -0
  367. package/src/surfaces/library-pane.json +1509 -0
  368. package/src/surfaces/library-pane.ts +363 -0
  369. package/src/surfaces/logic-panel.json +1949 -0
  370. package/src/surfaces/logic-panel.ts +369 -0
  371. package/src/surfaces/logic-workspace.json +685 -0
  372. package/src/surfaces/logic-workspace.ts +238 -0
  373. package/src/surfaces/media-browser.json +303 -0
  374. package/src/surfaces/media-browser.ts +145 -0
  375. package/src/surfaces/media-field.json +163 -0
  376. package/src/surfaces/media-field.ts +116 -0
  377. package/src/surfaces/media-pane.json +513 -0
  378. package/src/surfaces/media-pane.ts +197 -0
  379. package/src/surfaces/menu.json +232 -0
  380. package/src/surfaces/menu.ts +375 -0
  381. package/src/surfaces/navigator-dock.json +113 -0
  382. package/src/surfaces/navigator-dock.ts +130 -0
  383. package/src/surfaces/new-project.json +1654 -0
  384. package/src/surfaces/new-project.ts +411 -0
  385. package/src/surfaces/palette.json +535 -0
  386. package/src/surfaces/pane-context.json +1497 -0
  387. package/src/surfaces/pane-context.ts +513 -0
  388. package/src/surfaces/pane-grid.json +188 -0
  389. package/src/surfaces/pane-grid.ts +250 -0
  390. package/src/surfaces/panel-activity.json +563 -0
  391. package/src/surfaces/panel-activity.ts +187 -0
  392. package/src/surfaces/panel-data.json +141 -0
  393. package/src/surfaces/panel-data.ts +156 -0
  394. package/src/surfaces/panel-deploy-checklist.json +283 -0
  395. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  396. package/src/surfaces/panel-elements.json +367 -0
  397. package/src/surfaces/panel-elements.ts +175 -0
  398. package/src/surfaces/panel-i18n.json +569 -0
  399. package/src/surfaces/panel-i18n.ts +212 -0
  400. package/src/surfaces/panel-imports.json +780 -0
  401. package/src/surfaces/panel-imports.ts +209 -0
  402. package/src/surfaces/panel-outline.json +734 -0
  403. package/src/surfaces/panel-outline.ts +326 -0
  404. package/src/surfaces/panel-page.json +1017 -0
  405. package/src/surfaces/panel-page.ts +240 -0
  406. package/src/surfaces/panel-problems.json +497 -0
  407. package/src/surfaces/panel-problems.ts +157 -0
  408. package/src/surfaces/panel-signals.json +1973 -0
  409. package/src/surfaces/panel-signals.ts +436 -0
  410. package/src/surfaces/panel-stylebook-layers.json +317 -0
  411. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  412. package/src/surfaces/preferences.json +850 -0
  413. package/src/surfaces/preferences.ts +332 -0
  414. package/src/surfaces/progress-modal.json +110 -0
  415. package/src/surfaces/progress-modal.ts +150 -0
  416. package/src/surfaces/properties-panel.json +1578 -0
  417. package/src/surfaces/properties-panel.ts +337 -0
  418. package/src/surfaces/publish.json +945 -0
  419. package/src/surfaces/publish.ts +392 -0
  420. package/src/surfaces/push-plan.json +110 -0
  421. package/src/surfaces/push-plan.ts +87 -0
  422. package/src/surfaces/rail.json +255 -0
  423. package/src/surfaces/rail.ts +206 -0
  424. package/src/surfaces/reference-field.json +191 -0
  425. package/src/surfaces/reference-field.ts +168 -0
  426. package/src/surfaces/schema-builder.json +1011 -0
  427. package/src/surfaces/schema-builder.ts +181 -0
  428. package/src/surfaces/schema-form.json +1013 -0
  429. package/src/surfaces/schema-form.ts +287 -0
  430. package/src/surfaces/secret-field.json +60 -0
  431. package/src/surfaces/secret-field.ts +146 -0
  432. package/src/surfaces/seo.json +932 -0
  433. package/src/surfaces/seo.ts +334 -0
  434. package/src/surfaces/settings-contexts.json +538 -0
  435. package/src/surfaces/settings-contexts.ts +196 -0
  436. package/src/surfaces/settings-contributed.json +489 -0
  437. package/src/surfaces/settings-contributed.ts +199 -0
  438. package/src/surfaces/settings-css-vars.json +820 -0
  439. package/src/surfaces/settings-css-vars.ts +199 -0
  440. package/src/surfaces/settings-defs.json +1363 -0
  441. package/src/surfaces/settings-defs.ts +232 -0
  442. package/src/surfaces/settings-deploy.json +108 -0
  443. package/src/surfaces/settings-deploy.ts +135 -0
  444. package/src/surfaces/settings-extensions.json +486 -0
  445. package/src/surfaces/settings-extensions.ts +201 -0
  446. package/src/surfaces/settings-head.json +779 -0
  447. package/src/surfaces/settings-head.ts +397 -0
  448. package/src/surfaces/settings-locales.json +420 -0
  449. package/src/surfaces/settings-locales.ts +137 -0
  450. package/src/surfaces/settings-overview.json +423 -0
  451. package/src/surfaces/settings-overview.ts +218 -0
  452. package/src/surfaces/settings-packages.json +549 -0
  453. package/src/surfaces/settings-packages.ts +158 -0
  454. package/src/surfaces/settings-pane.json +147 -0
  455. package/src/surfaces/settings-pane.ts +150 -0
  456. package/src/surfaces/settings-rawjson.json +104 -0
  457. package/src/surfaces/settings-rawjson.ts +107 -0
  458. package/src/surfaces/shell.json +99 -0
  459. package/src/surfaces/shell.ts +30 -0
  460. package/src/surfaces/slash-menu.json +180 -0
  461. package/src/surfaces/slash-menu.ts +272 -0
  462. package/src/surfaces/statements.json +607 -0
  463. package/src/surfaces/statements.ts +238 -0
  464. package/src/surfaces/statusbar.json +94 -0
  465. package/src/{panels → surfaces}/statusbar.ts +163 -90
  466. package/src/surfaces/style-panel.json +1643 -0
  467. package/src/surfaces/style-panel.ts +338 -0
  468. package/src/surfaces/stylebook-chrome.json +122 -0
  469. package/src/surfaces/stylebook-chrome.ts +122 -0
  470. package/src/surfaces/tab-strip.json +448 -0
  471. package/src/surfaces/tab-strip.ts +200 -0
  472. package/src/surfaces/target-line.json +419 -0
  473. package/src/surfaces/target-line.ts +349 -0
  474. package/src/surfaces/toasts.json +189 -0
  475. package/src/surfaces/welcome.json +571 -0
  476. package/src/surfaces/welcome.ts +338 -0
  477. package/src/tabs/project-config.ts +71 -15
  478. package/src/tabs/tab.ts +52 -1
  479. package/src/types.ts +49 -3
  480. package/src/ui/ai-credentials-form.ts +104 -100
  481. package/src/ui/ai-managed-connect.ts +116 -49
  482. package/src/ui/ai-model-picker.ts +102 -47
  483. package/src/ui/cf-account-picker.ts +135 -0
  484. package/src/ui/color-selector.ts +80 -301
  485. package/src/ui/dynamic-slot.ts +43 -283
  486. package/src/ui/expression-editor.ts +797 -576
  487. package/src/ui/field-input.ts +8 -181
  488. package/src/ui/form-controls.ts +838 -366
  489. package/src/ui/formula-chips.ts +80 -85
  490. package/src/ui/kit.ts +33 -0
  491. package/src/ui/layers.ts +293 -593
  492. package/src/ui/media-picker.ts +203 -284
  493. package/src/ui/panel-resize.ts +251 -64
  494. package/src/ui/popover-surface.ts +153 -0
  495. package/src/ui/progress-modal.ts +22 -60
  496. package/src/ui/regions.ts +13 -7
  497. package/src/ui/schema-form.ts +906 -440
  498. package/src/ui/surface.ts +122 -0
  499. package/src/ui/unit-selector.ts +15 -131
  500. package/src/ui/value-source.ts +14 -0
  501. package/src/ui/virtual-window.ts +88 -9
  502. package/src/utils/canvas-media.ts +72 -0
  503. package/src/utils/edit-display.ts +7 -2
  504. package/src/utils/element-selectors.ts +69 -0
  505. package/src/utils/link-target.ts +2 -2
  506. package/src/utils/studio-utils.ts +0 -10
  507. package/src/view.ts +15 -0
  508. package/src/workspace/pane-derive.ts +36 -14
  509. package/src/workspace/workspace.ts +15 -6
  510. package/styles/canvas.css +72 -467
  511. package/styles/forced-colors.css +48 -82
  512. package/styles/forced-colors.json +41 -0
  513. package/styles/inspector.css +2 -1301
  514. package/styles/overlays.css +96 -2823
  515. package/styles/panels.css +6 -1423
  516. package/styles/shell-frame.css +272 -0
  517. package/styles/shell-frame.json +227 -0
  518. package/styles/shell.css +0 -1532
  519. package/styles/tokens.css +65 -136
  520. package/styles/tokens.json +84 -0
  521. package/dist/chunks/Overlay.dev-723bv0df.js +0 -23
  522. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  523. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  524. package/dist/chunks/components-zmx10t62.js +0 -21
  525. package/dist/chunks/content-source-t88vb2dr.js +0 -49
  526. package/dist/chunks/convert-to-repeater-dhw1nrz9.js +0 -268
  527. package/dist/chunks/editor-cptq5jp1.js +0 -37
  528. package/dist/chunks/entry-commands-6z6bhxg0.js +0 -46
  529. package/dist/chunks/extension-sections-3ydgjbdy.js +0 -311
  530. package/dist/chunks/file-ops-rskmhxyq.js +0 -48
  531. package/dist/chunks/files-0cratsr0.js +0 -92
  532. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  533. package/dist/chunks/focus-trap.esm-ggawf1hy.js +0 -1024
  534. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  535. package/dist/chunks/format-host-tgcmfs4p.js +0 -43
  536. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  537. package/dist/chunks/git-panel-0yywyk76.js +0 -58
  538. package/dist/chunks/index-zqxmqxmh.js +0 -109
  539. package/dist/chunks/jx-validate-8q2g05x1.js +0 -19
  540. package/dist/chunks/layers-panel-z3tqe5cd.js +0 -67
  541. package/dist/chunks/layers-q75tj2mf.js +0 -45
  542. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  543. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  544. package/dist/chunks/notify-yjm79n4s.js +0 -30
  545. package/dist/chunks/parse-24d0gay3.js +0 -19
  546. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  547. package/dist/chunks/publish-panel-54jvhskq.js +0 -28
  548. package/dist/chunks/quick-search-cgfmjwq5.js +0 -65
  549. package/dist/chunks/references-3qx8fkyp.js +0 -29
  550. package/dist/chunks/right-panel-cqp8bc4v.js +0 -46
  551. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  552. package/dist/chunks/sp-overlay.dev-yztmtrs1.js +0 -18
  553. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  554. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  555. package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +0 -15
  556. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  557. package/dist/chunks/studio-0a5qrh01.js +0 -3
  558. package/dist/chunks/studio-18j3bmcz.js +0 -14
  559. package/dist/chunks/studio-1hbqnt19.js +0 -1823
  560. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  561. package/dist/chunks/studio-5rywrkxz.js +0 -1903
  562. package/dist/chunks/studio-7afd21nw.js +0 -67
  563. package/dist/chunks/studio-7nte2hj4.js +0 -613
  564. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  565. package/dist/chunks/studio-8q517dfr.js +0 -24
  566. package/dist/chunks/studio-9c4k4vhv.js +0 -357
  567. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  568. package/dist/chunks/studio-a0tswy0w.js +0 -58
  569. package/dist/chunks/studio-ahjfdy6e.js +0 -387
  570. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  571. package/dist/chunks/studio-bw5dz6km.js +0 -608
  572. package/dist/chunks/studio-cb12yz9w.js +0 -15055
  573. package/dist/chunks/studio-d1ks410h.js +0 -175
  574. package/dist/chunks/studio-eqq1w638.js +0 -113
  575. package/dist/chunks/studio-ex8zyp98.js +0 -1813
  576. package/dist/chunks/studio-h4rxscfc.js +0 -10
  577. package/dist/chunks/studio-kyh9avvv.js +0 -28
  578. package/dist/chunks/studio-kyk2v92a.js +0 -659
  579. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  580. package/dist/chunks/studio-mmv72a27.js +0 -4344
  581. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  582. package/dist/chunks/studio-pdfjntbk.js +0 -6939
  583. package/dist/chunks/studio-qq6jym04.js +0 -53
  584. package/dist/chunks/studio-r1r7afxx.js +0 -1066
  585. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  586. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  587. package/dist/chunks/studio-t7qb9db8.js +0 -665
  588. package/dist/chunks/studio-tmc5emrw.js +0 -8
  589. package/dist/chunks/studio-txwkm6p9.js +0 -12
  590. package/dist/chunks/studio-v38hmvx1.js +0 -390
  591. package/dist/chunks/studio-vadzgkrz.js +0 -318
  592. package/dist/chunks/studio-wx5609xd.js +0 -341
  593. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  594. package/dist/chunks/studio-zczps70q.js +0 -378
  595. package/dist/chunks/workspace-xpres40v.js +0 -89
  596. package/src/panels/activity-bar.ts +0 -251
  597. package/src/panels/panel-scheduler.ts +0 -219
  598. package/src/panels/style-inputs.ts +0 -237
  599. package/src/panels/target-line.ts +0 -274
  600. package/src/panels/welcome-screen.ts +0 -346
  601. package/src/ui/button-group.ts +0 -102
  602. package/src/ui/choice-field.ts +0 -72
  603. package/src/ui/field-row.ts +0 -249
  604. package/src/ui/formula-palette.ts +0 -213
  605. package/src/ui/icons.ts +0 -52
  606. package/src/ui/jx-theme.ts +0 -130
  607. package/src/ui/spectrum.ts +0 -340
  608. package/src/ui/value-selector.ts +0 -174
  609. package/src/ui/widgets.ts +0 -172
  610. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  611. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  612. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  613. /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
@@ -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
+ }
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import type { createChatState } from "@jxsuite/ai/chat-state";
15
+ import { modelContextWindow } from "./ai-models";
15
16
 
16
17
  /** Shape of a single entry returned by `chatState.toMessagesArray()`. */
17
18
  interface MessageArrayEntry {
@@ -52,7 +53,13 @@ const BUDGET_FRACTION = 0.8;
52
53
  const WARN_FRACTION = 0.5;
53
54
 
54
55
  /**
55
- * Resolve the context window (tokens) for a model id via longest-prefix match.
56
+ * Resolve the context window (tokens) for a model id: what the backend reported, else a
57
+ * longest-prefix match on the table above, else the conservative default.
58
+ *
59
+ * The backend's number goes first because the table can only ever know the names it was written
60
+ * with. Every `@cf/*` model missed it and was budgeted at {@link DEFAULT_CONTEXT_WINDOW}, so a
61
+ * managed 128k model started dropping the oldest turns at about 25.6k — a fifth of what it could
62
+ * hold, on the one backend that actually publishes the figure.
56
63
  *
57
64
  * @param {string | undefined} model
58
65
  * @returns {number}
@@ -61,6 +68,10 @@ function contextWindowFor(model: string | undefined): number {
61
68
  if (!model) {
62
69
  return DEFAULT_CONTEXT_WINDOW;
63
70
  }
71
+ const reported = modelContextWindow(model);
72
+ if (reported !== undefined && reported > 0) {
73
+ return reported;
74
+ }
64
75
  const id = model.toLowerCase();
65
76
  let best = 0;
66
77
  let window = DEFAULT_CONTEXT_WINDOW;
@@ -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";
42
+ import { validateDoc } from "./jx-validate";
36
43
  import { openFileInTab, reloadFileInTab } from "../files/files";
37
- import { refreshExtensionUi } from "../format/format-host";
44
+ import { getExtensionCatalog, refreshExtensionUi } from "../format/format-host";
38
45
  import * as sessionStore from "./ai-session-store";
39
46
 
40
47
  /**
@@ -189,7 +196,26 @@ export function createDocumentAssistant() {
189
196
  },
190
197
  ]),
191
198
  );
192
- const toolRegistry = createGatedToolRegistry(innerRegistry, availability);
199
+ /*
200
+ * The other kind of tool: every command record that declares `aiTool`, as a VIEW over the active
201
+ * registry (`services/ai-command-tools.ts`). Nothing is registered — the record IS the tool, its
202
+ * `when` / `enablement` is the gate, `registry.run` is the executor — so `enable_extension`,
203
+ * `delete_node` and the rest need no row in the tier table and no registrar here. The deps are
204
+ * the write reporter's, the same three the hand tree tools take, because a bridged document write
205
+ * is held to the same verdict (new schema errors, the render check, the token hints).
206
+ */
207
+ const commandTools = createCommandToolRegistry({
208
+ getProjectStyle,
209
+ getTab: () => activeTab.value,
210
+ renderCheck: renderCheck as (
211
+ doc: unknown,
212
+ ) => Promise<{ ok: true } | { ok: false; error: string }>,
213
+ validate: validateDoc,
214
+ });
215
+ const toolRegistry = composeToolRegistries(
216
+ createGatedToolRegistry(innerRegistry, availability),
217
+ commandTools,
218
+ );
193
219
 
194
220
  let controller: AbortController | null = null;
195
221
 
@@ -201,6 +227,19 @@ export function createDocumentAssistant() {
201
227
  .filter((e) => e.type === "file")
202
228
  .map((e) => e.path)
203
229
  : undefined;
230
+ /* The synchronous snapshot beside the async load, exactly as `getExtensions()` sits beside
231
+ `loadExtensions()`: `buildSystemPrompt` is a pure function and this is called per turn, so
232
+ the catalogue is read from the ONE cache the Extensions section also reads. Two caches would
233
+ be two answers to "what can this project turn on". */
234
+ const catalog: ExtensionCatalogSummary[] = [];
235
+ for (const entry of getExtensionCatalog()) {
236
+ catalog.push({
237
+ name: entry.name,
238
+ sections: entry.sections.map((section) => section.key),
239
+ ...(entry.title === undefined ? {} : { title: entry.title }),
240
+ ...(entry.description === undefined ? {} : { description: entry.description }),
241
+ });
242
+ }
204
243
  return buildSystemPrompt({
205
244
  document: tab ? toRaw(tab.doc.document) : undefined,
206
245
  projectConfig: (workspace.projectConfig as ProjectConfig | null) || undefined,
@@ -208,7 +247,16 @@ export function createDocumentAssistant() {
208
247
  projectRoot: workspace.projectRoot || undefined,
209
248
  hasProject: Boolean(workspace.projectRoot),
210
249
  canImport: Boolean(getPlatform().importSite),
250
+ /* The same reading the gate makes, so the prompt advertises exactly what `execute` will
251
+ honour. This was never passed: with Project Settings focused the prompt listed the seven
252
+ hand tree writers while the `document-tree` gate refused every one of them, and the model
253
+ spent a round learning it. */
254
+ treeEditable: treeEditable(),
255
+ /* Read per turn from the live registry — a projected tool the gate will honour this round is
256
+ listed this round, and one it will not is not. */
257
+ commandTools: commandToolBlurbs(activeRegistry()),
211
258
  ...(inventory && inventory.length > 0 ? { fileInventory: inventory } : {}),
259
+ ...(catalog.length > 0 ? { extensionCatalog: catalog } : {}),
212
260
  });
213
261
  }
214
262
 
@@ -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: () => {