@jxsuite/studio 4.1.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (612) hide show
  1. package/README.md +1 -1
  2. package/data/elements-meta.json +5 -15
  3. package/data/html-meta.json +51 -6
  4. package/dist/chunks/{2020-n6tfwnda.js → 2020-g79n01v9.js} +14 -14
  5. package/dist/chunks/action-group-sp6tna8v.js +118 -0
  6. package/dist/chunks/adapter-nj7tnjfn.js +13 -0
  7. package/dist/chunks/cf-account-picker-qwkm9zrf.js +495 -0
  8. package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
  9. package/dist/chunks/color-area-v17df7b8.js +154 -0
  10. package/dist/chunks/color-field-anwybnkn.js +208 -0
  11. package/dist/chunks/color-slider-44ez96fc.js +79 -0
  12. package/dist/chunks/color-xgg3kfw7.js +35 -0
  13. package/dist/chunks/combobox-5e7jev23.js +236 -0
  14. package/dist/chunks/components-vj72gqtq.js +20 -0
  15. package/dist/chunks/content-source-5mex4x1h.js +46 -0
  16. package/dist/chunks/convert-to-repeater-n64h8znc.js +639 -0
  17. package/dist/chunks/dialog-s890b918.js +85 -0
  18. package/dist/chunks/editor-3qhbg51x.js +35 -0
  19. package/dist/chunks/entry-commands-234hjnqw.js +42 -0
  20. package/dist/chunks/extension-sections-3hpcambp.js +651 -0
  21. package/dist/chunks/file-ops-8yhd83xr.js +47 -0
  22. package/dist/chunks/files-hnxqxtsg.js +72 -0
  23. package/dist/chunks/format-host-779sfp2n.js +40 -0
  24. package/dist/chunks/fs-events-b88z7g4h.js +18 -0
  25. package/dist/chunks/git-panel-xwj8fpab.js +49 -0
  26. package/dist/chunks/icons-yy10wk9r.js +402 -0
  27. package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
  28. package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
  29. package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
  30. package/dist/chunks/iframe-host-syr0f9sb.js +115 -0
  31. package/dist/chunks/{index-wcnt3r9g.js → index-mdmyx6s2.js} +11 -11
  32. package/dist/chunks/index-n4j7qxyr.js +109 -0
  33. package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
  34. package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
  35. package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
  36. package/dist/chunks/layers-ff81wthn.js +30 -0
  37. package/dist/chunks/layers-panel-pnnghw12.js +40 -0
  38. package/dist/chunks/listbox-6v2ac08j.js +44 -0
  39. package/dist/chunks/lit-html-m244w9nh.js +17 -0
  40. package/dist/chunks/media-picker-cqhhxhhe.js +33 -0
  41. package/dist/chunks/menu-9p2w46gj.js +15 -0
  42. package/dist/chunks/menu-q99sy9rf.js +285 -0
  43. package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
  44. package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
  45. package/dist/chunks/{monaco-setup-vx9bhp1d.js → monaco-setup-8r62fj6y.js} +27 -37
  46. package/dist/chunks/notify-628t0anh.js +21 -0
  47. package/dist/chunks/number-field-5cndyft8.js +72 -0
  48. package/dist/chunks/parse-0zx14y15.js +10 -0
  49. package/dist/chunks/platform-ts9cg1a4.js +15 -0
  50. package/dist/chunks/popover-47z3ytva.js +25 -0
  51. package/dist/chunks/publish-panel-5zt840sy.js +27 -0
  52. package/dist/chunks/quick-search-3748564r.js +45 -0
  53. package/dist/chunks/references-qvvxej7h.js +26 -0
  54. package/dist/chunks/right-panel-eccz92qt.js +45 -0
  55. package/dist/chunks/section-registry-5pq32t0q.js +25 -0
  56. package/dist/chunks/select-2r16ez41.js +49 -0
  57. package/dist/chunks/split-g7nm1rgb.js +191 -0
  58. package/dist/chunks/studio-0hqbpbd0.js +62 -0
  59. package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
  60. package/dist/chunks/{studio-b55y6ewx.js → studio-1knfqgy7.js} +58 -58
  61. package/dist/chunks/{studio-2b946z26.js → studio-1z1kcjv4.js} +3628 -6095
  62. package/dist/chunks/studio-3773086z.js +111 -0
  63. package/dist/chunks/{studio-4r1pv6zf.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/{studio-x813zp48.js → studio-3rz5md06.js} +30 -30
  65. package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
  66. package/dist/chunks/studio-5te5tqng.js +81 -0
  67. package/dist/chunks/studio-5wt9nvhd.js +4763 -0
  68. package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
  69. package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
  70. package/dist/chunks/studio-6xa21ej9.js +28 -0
  71. package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
  72. package/dist/chunks/{studio-gcye7qka.js → studio-7e11jpa9.js} +21 -21
  73. package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
  74. package/dist/chunks/studio-7xnmgv66.js +13615 -0
  75. package/dist/chunks/studio-8scdew0e.js +258 -0
  76. package/dist/chunks/{studio-fbf92ckf.js → studio-93zafjcm.js} +275 -163
  77. package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
  78. package/dist/chunks/studio-a79k90n9.js +1162 -0
  79. package/dist/chunks/studio-aj37eer3.js +422 -0
  80. package/dist/chunks/studio-b0k5tqgp.js +2432 -0
  81. package/dist/chunks/studio-b4s9eykd.js +2811 -0
  82. package/dist/chunks/{studio-f3wqjtk5.js → studio-d0300636.js} +5076 -18
  83. package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
  84. package/dist/chunks/studio-e1pgga3k.js +839 -0
  85. package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
  86. package/dist/chunks/{studio-q43a5y9h.js → studio-g3jevyjt.js} +16 -16
  87. package/dist/chunks/studio-gb13095a.js +2806 -0
  88. package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
  89. package/dist/chunks/{studio-dm19q43r.js → studio-hhvs4sdg.js} +10 -10
  90. package/dist/chunks/{studio-x4qkdat5.js → studio-js8nv53n.js} +1749 -2481
  91. package/dist/chunks/{studio-qjy2z9bv.js → studio-jxp12rnj.js} +32 -137
  92. package/dist/chunks/{studio-trxrabqf.js → studio-k75n7vhp.js} +527 -283
  93. package/dist/chunks/{studio-q9jd1a60.js → studio-kcgff4r0.js} +15 -18
  94. package/dist/chunks/studio-kkqkcp3d.js +17668 -0
  95. package/dist/chunks/studio-mhhyamxf.js +763 -0
  96. package/dist/chunks/{studio-cft9r4r7.js → studio-nq5yf5mp.js} +22 -22
  97. package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
  98. package/dist/chunks/studio-nzzpvzx9.js +185 -0
  99. package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
  100. package/dist/chunks/{studio-3bqpr0zh.js → studio-pxbgypmg.js} +299 -110
  101. package/dist/chunks/studio-q0a3yk4n.js +33 -0
  102. package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
  103. package/dist/chunks/{studio-6yw4y3my.js → studio-qhhm6hbt.js} +8 -8
  104. package/dist/chunks/studio-qk4bfsq2.js +362 -0
  105. package/dist/chunks/{studio-msd847zn.js → studio-qk90fgqm.js} +361 -90
  106. package/dist/chunks/{studio-jkftxyvz.js → studio-r6nvacqs.js} +5861 -2154
  107. package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
  108. package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
  109. package/dist/chunks/studio-rs76k67r.js +12 -0
  110. package/dist/chunks/studio-sbjyc8bt.js +954 -0
  111. package/dist/chunks/{studio-1wagb550.js → studio-syg2tadj.js} +11 -11
  112. package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
  113. package/dist/chunks/studio-tqgryxwg.js +1171 -0
  114. package/dist/chunks/studio-try13h8c.js +8448 -0
  115. package/dist/chunks/studio-vfq8qpjt.js +1219 -0
  116. package/dist/chunks/studio-vhv5tgxm.js +51 -0
  117. package/dist/chunks/{studio-ahn3pdgx.js → studio-vw7mzp6z.js} +52 -38
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/studio-wqz6dggm.js +1356 -0
  120. package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
  121. package/dist/chunks/studio-yxa81f45.js +12 -0
  122. package/dist/chunks/studio-zdn2g6dt.js +148 -0
  123. package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
  124. package/dist/chunks/tabs-wbp1cdws.js +156 -0
  125. package/dist/chunks/textfield-abk6qyee.js +73 -0
  126. package/dist/chunks/toast-780pvfbv.js +27 -0
  127. package/dist/chunks/toast-host-3sqv46sn.js +116 -0
  128. package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
  129. package/dist/chunks/tooltip-eptb614w.js +369 -0
  130. package/dist/chunks/tree-a73p0pqm.js +367 -0
  131. package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
  132. package/dist/chunks/workspace-t55jdjbx.js +69 -0
  133. package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
  134. package/dist/iframe-entry.js +1873 -673
  135. package/dist/studio.js +52757 -36535
  136. package/dist/workers/editor.worker.js +1040 -1085
  137. package/dist/workers/json.worker.js +1946 -1991
  138. package/dist/workers/ts.worker.js +4960 -5005
  139. package/index.html +1 -0
  140. package/package.json +18 -52
  141. package/src/about/about-modal.ts +72 -123
  142. package/src/browse/library-commands.ts +20 -49
  143. package/src/browse/library-layouts.ts +87 -218
  144. package/src/browse/library-pane.ts +406 -438
  145. package/src/canvas/canvas-helpers.ts +0 -49
  146. package/src/canvas/canvas-live-render.ts +25 -2
  147. package/src/canvas/canvas-render.ts +666 -231
  148. package/src/canvas/canvas-surface.ts +0 -1
  149. package/src/canvas/canvas-utils.ts +333 -113
  150. package/src/canvas/dialog-path.ts +76 -0
  151. package/src/canvas/dialog-state.ts +67 -0
  152. package/src/canvas/diff-marks.ts +252 -0
  153. package/src/canvas/diff-toolbar.ts +349 -0
  154. package/src/canvas/diff-view.ts +123 -0
  155. package/src/canvas/edit-width-drag.ts +187 -0
  156. package/src/canvas/edit-width.ts +150 -0
  157. package/src/canvas/iframe-entry.ts +125 -8
  158. package/src/canvas/iframe-host.ts +271 -15
  159. package/src/canvas/iframe-interaction.ts +133 -13
  160. package/src/canvas/iframe-patch.ts +7 -1
  161. package/src/canvas/iframe-position.ts +5 -6
  162. package/src/canvas/iframe-protocol.ts +106 -5
  163. package/src/canvas/iframe-render.ts +373 -5
  164. package/src/canvas/iframe-slash.ts +2 -2
  165. package/src/canvas/iframe-subtree.ts +5 -8
  166. package/src/canvas/path-mapping.ts +25 -3
  167. package/src/canvas/popover-path.ts +106 -0
  168. package/src/canvas/popover-state.ts +155 -0
  169. package/src/canvas/surface-registry.ts +21 -10
  170. package/src/collab/presence-chips.ts +51 -73
  171. package/src/commands/app-commands.ts +10 -0
  172. package/src/commands/budget.ts +12 -0
  173. package/src/commands/command-args.ts +404 -6
  174. package/src/commands/defaults.ts +44 -14
  175. package/src/commands/live-context.ts +11 -5
  176. package/src/commands/reference.ts +12 -2
  177. package/src/commands/registry.ts +177 -10
  178. package/src/commands/run-reported.ts +120 -0
  179. package/src/content/entry-commands.ts +16 -23
  180. package/src/content/entry-editor.ts +144 -101
  181. package/src/editor/canvas-slash-bridge.ts +2 -2
  182. package/src/editor/context-menu.ts +49 -200
  183. package/src/editor/convert-to-component.ts +42 -82
  184. package/src/editor/convert-to-repeater.ts +132 -173
  185. package/src/editor/inline-edit.ts +11 -0
  186. package/src/editor/shortcuts.ts +76 -49
  187. package/src/editor/slash-menu.ts +150 -157
  188. package/src/files/components.ts +39 -0
  189. package/src/files/file-ops.ts +117 -11
  190. package/src/files/files.ts +944 -660
  191. package/src/files/json-layout.ts +474 -0
  192. package/src/files/serialize-document.ts +8 -1
  193. package/src/format/convert-file.ts +16 -10
  194. package/src/format/format-host.ts +50 -1
  195. package/src/github/github-auth.ts +71 -29
  196. package/src/github/github-publish.ts +57 -65
  197. package/src/grid/cell-editors.ts +46 -4
  198. package/src/grid/cell-popovers.ts +65 -62
  199. package/src/grid/grid-open.ts +86 -64
  200. package/src/grid/grid-panel.ts +390 -469
  201. package/src/grid/redirects-grid.ts +40 -44
  202. package/src/hosting/layout.ts +2 -0
  203. package/src/i18n/i18n-commands.ts +137 -62
  204. package/src/media/media-pane.ts +83 -133
  205. package/src/new-project/add-repo-modal.ts +125 -176
  206. package/src/new-project/import-tab.ts +181 -252
  207. package/src/new-project/location-fields.ts +93 -160
  208. package/src/new-project/new-project-modal.ts +376 -367
  209. package/src/packages/jxsuite-update.ts +76 -18
  210. package/src/packages/pull-package-sync.ts +5 -1
  211. package/src/panels/activity-panel.ts +137 -104
  212. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  213. package/src/panels/ai-chat/chat-view.ts +307 -472
  214. package/src/panels/ai-chat/composer.ts +175 -163
  215. package/src/panels/ai-chat/sessions-view.ts +31 -62
  216. package/src/panels/ai-panel.ts +213 -185
  217. package/src/panels/block-action-bar.ts +444 -645
  218. package/src/panels/bottom-dock.ts +112 -47
  219. package/src/panels/chat-panel.ts +19 -14
  220. package/src/panels/data-explorer.ts +141 -102
  221. package/src/panels/data-grid.ts +183 -150
  222. package/src/panels/dnd.ts +75 -20
  223. package/src/panels/editors.ts +26 -19
  224. package/src/panels/elements-panel.ts +243 -186
  225. package/src/panels/empty-state.ts +26 -42
  226. package/src/panels/events-panel.ts +950 -729
  227. package/src/panels/formula-workspace.ts +434 -207
  228. package/src/panels/frontmatter-fields.ts +185 -153
  229. package/src/panels/frontmatter-panel.ts +411 -187
  230. package/src/panels/git-diff-open.ts +148 -0
  231. package/src/panels/git-panel.ts +679 -605
  232. package/src/panels/head-panel.ts +617 -435
  233. package/src/panels/i18n-panel.ts +148 -135
  234. package/src/panels/imports-panel.ts +388 -414
  235. package/src/panels/jump-bar.ts +175 -147
  236. package/src/panels/layers-panel.ts +785 -671
  237. package/src/panels/left-panel.ts +166 -94
  238. package/src/panels/navigator-panels.ts +1 -1
  239. package/src/panels/pane-context.ts +529 -677
  240. package/src/panels/pane-grid.ts +265 -241
  241. package/src/panels/panel-registry.ts +15 -4
  242. package/src/panels/problems-panel.ts +181 -99
  243. package/src/panels/properties-panel.ts +1525 -966
  244. package/src/panels/provenance.ts +31 -113
  245. package/src/panels/quick-search.ts +223 -184
  246. package/src/panels/right-panel.ts +135 -169
  247. package/src/panels/seo-modal.ts +346 -167
  248. package/src/panels/settings-menu.ts +114 -661
  249. package/src/panels/settings-pane.ts +102 -86
  250. package/src/panels/signals-panel.ts +1318 -1172
  251. package/src/panels/statement-editor.ts +556 -428
  252. package/src/panels/style-panel.ts +1367 -630
  253. package/src/panels/style-utils.ts +36 -32
  254. package/src/panels/stylebook-doc.ts +30 -73
  255. package/src/panels/stylebook-layers-panel.ts +202 -109
  256. package/src/panels/stylebook-panel.ts +124 -88
  257. package/src/panels/tab-strip.ts +386 -288
  258. package/src/platforms/cloud.ts +106 -16
  259. package/src/platforms/devserver.ts +13 -0
  260. package/src/publish/deploy-checklist.ts +124 -78
  261. package/src/publish/publish-commands.ts +4 -12
  262. package/src/publish/publish-panel.ts +134 -328
  263. package/src/services/a11y-report.ts +100 -43
  264. package/src/services/ai-command-tools.ts +538 -0
  265. package/src/services/ai-project-tools.ts +8 -2
  266. package/src/services/ai-session-store.ts +6 -0
  267. package/src/services/ai-system-prompt.ts +112 -24
  268. package/src/services/ai-tools.ts +36 -212
  269. package/src/services/ai-write-report.ts +174 -0
  270. package/src/services/document-assistant.ts +59 -8
  271. package/src/services/idle.ts +16 -14
  272. package/src/services/live-surfaces.ts +237 -0
  273. package/src/services/model-uri.ts +75 -0
  274. package/src/services/notify.ts +63 -6
  275. package/src/services/popover-report.ts +325 -0
  276. package/src/services/surface-registry.ts +56 -0
  277. package/src/services/tool-executor.ts +6 -0
  278. package/src/settings/contexts-section.ts +301 -299
  279. package/src/settings/contributed-section.ts +361 -222
  280. package/src/settings/css-vars-editor.ts +320 -325
  281. package/src/settings/defs-editor.ts +572 -535
  282. package/src/settings/dependencies-editor.ts +79 -107
  283. package/src/settings/extension-commands.ts +379 -0
  284. package/src/settings/extension-rows.ts +113 -0
  285. package/src/settings/extensions-section.ts +287 -0
  286. package/src/settings/general-settings.ts +130 -181
  287. package/src/settings/head-editor.ts +10 -305
  288. package/src/settings/locales-section.ts +146 -196
  289. package/src/settings/preferences-accounts.ts +1 -1
  290. package/src/settings/preferences-dialog.ts +350 -330
  291. package/src/settings/project-sections.ts +108 -181
  292. package/src/settings/schema-field-ui.ts +11 -399
  293. package/src/settings/section-registry.ts +8 -1
  294. package/src/settings/settings-document.ts +31 -29
  295. package/src/shell/tree.ts +42 -87
  296. package/src/shell.ts +48 -36
  297. package/src/studio.ts +104 -69
  298. package/src/style/token-ref.ts +0 -39
  299. package/src/surfaces/about.json +263 -0
  300. package/src/surfaces/about.ts +163 -0
  301. package/src/surfaces/add-repo.json +486 -0
  302. package/src/surfaces/add-repo.ts +236 -0
  303. package/src/surfaces/ai-chat.json +2185 -0
  304. package/src/surfaces/ai-chat.ts +549 -0
  305. package/src/surfaces/ai-credentials-form.json +332 -0
  306. package/src/surfaces/ai-credentials-form.ts +151 -0
  307. package/src/surfaces/ai-managed-connect.json +108 -0
  308. package/src/surfaces/ai-managed-connect.ts +123 -0
  309. package/src/surfaces/ai-model-picker.json +114 -0
  310. package/src/surfaces/ai-model-picker.ts +139 -0
  311. package/src/surfaces/block-action-bar.json +640 -0
  312. package/src/surfaces/block-action-bar.ts +368 -0
  313. package/src/surfaces/bottom-dock.json +154 -0
  314. package/src/surfaces/bottom-dock.ts +125 -0
  315. package/src/surfaces/canvas-stage.json +444 -0
  316. package/src/surfaces/canvas-stage.ts +253 -0
  317. package/src/surfaces/cf-account-picker.json +300 -0
  318. package/src/surfaces/cf-account-picker.ts +214 -0
  319. package/src/surfaces/commandbar.json +985 -0
  320. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +417 -391
  321. package/src/surfaces/convert-repeater.json +309 -0
  322. package/src/surfaces/convert-repeater.ts +276 -0
  323. package/src/surfaces/data-actions.json +157 -0
  324. package/src/surfaces/data-actions.ts +115 -0
  325. package/src/surfaces/dialog.json +289 -0
  326. package/src/surfaces/dialog.ts +343 -0
  327. package/src/surfaces/diff-toolbar.json +266 -0
  328. package/src/surfaces/diff-toolbar.ts +139 -0
  329. package/src/surfaces/doc-header.json +739 -0
  330. package/src/surfaces/doc-header.ts +223 -0
  331. package/src/surfaces/empty-state.json +152 -0
  332. package/src/surfaces/empty-state.ts +173 -0
  333. package/src/surfaces/entry-editor.json +281 -0
  334. package/src/surfaces/entry-editor.ts +191 -0
  335. package/src/surfaces/expression-editor.json +977 -0
  336. package/src/surfaces/expression-editor.ts +266 -0
  337. package/src/surfaces/files-panel.json +592 -0
  338. package/src/surfaces/files-panel.ts +301 -0
  339. package/src/surfaces/formula-palette.json +364 -0
  340. package/src/surfaces/formula-palette.ts +340 -0
  341. package/src/surfaces/git-panel.json +1822 -0
  342. package/src/surfaces/git-panel.ts +272 -0
  343. package/src/surfaces/github-auth.json +112 -0
  344. package/src/surfaces/github-auth.ts +139 -0
  345. package/src/surfaces/github-publish.json +206 -0
  346. package/src/surfaces/github-publish.ts +169 -0
  347. package/src/surfaces/grid-cell.json +218 -0
  348. package/src/surfaces/grid-cell.ts +120 -0
  349. package/src/surfaces/grid-open.json +147 -0
  350. package/src/surfaces/grid-open.ts +87 -0
  351. package/src/surfaces/grid-panel.json +706 -0
  352. package/src/surfaces/grid-panel.ts +206 -0
  353. package/src/surfaces/grid-replace.json +179 -0
  354. package/src/surfaces/grid-replace.ts +89 -0
  355. package/src/surfaces/grid-views.json +446 -0
  356. package/src/surfaces/grid-views.ts +172 -0
  357. package/src/surfaces/inspector-dock.json +187 -0
  358. package/src/surfaces/inspector-dock.ts +161 -0
  359. package/src/surfaces/jump-bar.json +243 -0
  360. package/src/surfaces/jump-bar.ts +129 -0
  361. package/src/surfaces/jxsuite-update.json +146 -0
  362. package/src/surfaces/jxsuite-update.ts +149 -0
  363. package/src/surfaces/library-pane.json +1509 -0
  364. package/src/surfaces/library-pane.ts +363 -0
  365. package/src/surfaces/logic-panel.json +1949 -0
  366. package/src/surfaces/logic-panel.ts +369 -0
  367. package/src/surfaces/logic-workspace.json +685 -0
  368. package/src/surfaces/logic-workspace.ts +238 -0
  369. package/src/surfaces/media-browser.json +303 -0
  370. package/src/surfaces/media-browser.ts +145 -0
  371. package/src/surfaces/media-field.json +163 -0
  372. package/src/surfaces/media-field.ts +116 -0
  373. package/src/surfaces/media-pane.json +513 -0
  374. package/src/surfaces/media-pane.ts +197 -0
  375. package/src/surfaces/menu.json +232 -0
  376. package/src/surfaces/menu.ts +375 -0
  377. package/src/surfaces/navigator-dock.json +113 -0
  378. package/src/surfaces/navigator-dock.ts +130 -0
  379. package/src/surfaces/new-project.json +1654 -0
  380. package/src/surfaces/new-project.ts +411 -0
  381. package/src/surfaces/palette.json +535 -0
  382. package/src/surfaces/pane-context.json +1497 -0
  383. package/src/surfaces/pane-context.ts +513 -0
  384. package/src/surfaces/pane-grid.json +188 -0
  385. package/src/surfaces/pane-grid.ts +250 -0
  386. package/src/surfaces/panel-activity.json +563 -0
  387. package/src/surfaces/panel-activity.ts +187 -0
  388. package/src/surfaces/panel-data.json +141 -0
  389. package/src/surfaces/panel-data.ts +156 -0
  390. package/src/surfaces/panel-deploy-checklist.json +283 -0
  391. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  392. package/src/surfaces/panel-elements.json +367 -0
  393. package/src/surfaces/panel-elements.ts +175 -0
  394. package/src/surfaces/panel-i18n.json +569 -0
  395. package/src/surfaces/panel-i18n.ts +212 -0
  396. package/src/surfaces/panel-imports.json +780 -0
  397. package/src/surfaces/panel-imports.ts +209 -0
  398. package/src/surfaces/panel-outline.json +734 -0
  399. package/src/surfaces/panel-outline.ts +326 -0
  400. package/src/surfaces/panel-page.json +1017 -0
  401. package/src/surfaces/panel-page.ts +240 -0
  402. package/src/surfaces/panel-problems.json +497 -0
  403. package/src/surfaces/panel-problems.ts +157 -0
  404. package/src/surfaces/panel-signals.json +1973 -0
  405. package/src/surfaces/panel-signals.ts +436 -0
  406. package/src/surfaces/panel-stylebook-layers.json +317 -0
  407. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  408. package/src/surfaces/preferences.json +850 -0
  409. package/src/surfaces/preferences.ts +332 -0
  410. package/src/surfaces/progress-modal.json +110 -0
  411. package/src/surfaces/progress-modal.ts +150 -0
  412. package/src/surfaces/properties-panel.json +1578 -0
  413. package/src/surfaces/properties-panel.ts +337 -0
  414. package/src/surfaces/publish.json +945 -0
  415. package/src/surfaces/publish.ts +392 -0
  416. package/src/surfaces/push-plan.json +110 -0
  417. package/src/surfaces/push-plan.ts +87 -0
  418. package/src/surfaces/rail.json +255 -0
  419. package/src/surfaces/rail.ts +206 -0
  420. package/src/surfaces/reference-field.json +191 -0
  421. package/src/surfaces/reference-field.ts +168 -0
  422. package/src/surfaces/schema-builder.json +1011 -0
  423. package/src/surfaces/schema-builder.ts +181 -0
  424. package/src/surfaces/schema-form.json +1013 -0
  425. package/src/surfaces/schema-form.ts +287 -0
  426. package/src/surfaces/secret-field.json +60 -0
  427. package/src/surfaces/secret-field.ts +146 -0
  428. package/src/surfaces/seo.json +932 -0
  429. package/src/surfaces/seo.ts +334 -0
  430. package/src/surfaces/settings-contexts.json +538 -0
  431. package/src/surfaces/settings-contexts.ts +196 -0
  432. package/src/surfaces/settings-contributed.json +489 -0
  433. package/src/surfaces/settings-contributed.ts +199 -0
  434. package/src/surfaces/settings-css-vars.json +820 -0
  435. package/src/surfaces/settings-css-vars.ts +199 -0
  436. package/src/surfaces/settings-defs.json +1363 -0
  437. package/src/surfaces/settings-defs.ts +232 -0
  438. package/src/surfaces/settings-deploy.json +108 -0
  439. package/src/surfaces/settings-deploy.ts +135 -0
  440. package/src/surfaces/settings-extensions.json +486 -0
  441. package/src/surfaces/settings-extensions.ts +201 -0
  442. package/src/surfaces/settings-head.json +779 -0
  443. package/src/surfaces/settings-head.ts +397 -0
  444. package/src/surfaces/settings-locales.json +420 -0
  445. package/src/surfaces/settings-locales.ts +137 -0
  446. package/src/surfaces/settings-overview.json +423 -0
  447. package/src/surfaces/settings-overview.ts +218 -0
  448. package/src/surfaces/settings-packages.json +549 -0
  449. package/src/surfaces/settings-packages.ts +158 -0
  450. package/src/surfaces/settings-pane.json +147 -0
  451. package/src/surfaces/settings-pane.ts +150 -0
  452. package/src/surfaces/settings-rawjson.json +104 -0
  453. package/src/surfaces/settings-rawjson.ts +107 -0
  454. package/src/surfaces/shell.json +99 -0
  455. package/src/surfaces/shell.ts +30 -0
  456. package/src/surfaces/slash-menu.json +180 -0
  457. package/src/surfaces/slash-menu.ts +272 -0
  458. package/src/surfaces/statements.json +607 -0
  459. package/src/surfaces/statements.ts +238 -0
  460. package/src/surfaces/statusbar.json +94 -0
  461. package/src/{panels → surfaces}/statusbar.ts +164 -90
  462. package/src/surfaces/style-panel.json +1643 -0
  463. package/src/surfaces/style-panel.ts +338 -0
  464. package/src/surfaces/stylebook-chrome.json +122 -0
  465. package/src/surfaces/stylebook-chrome.ts +122 -0
  466. package/src/surfaces/tab-strip.json +448 -0
  467. package/src/surfaces/tab-strip.ts +200 -0
  468. package/src/surfaces/target-line.json +419 -0
  469. package/src/surfaces/target-line.ts +349 -0
  470. package/src/surfaces/toasts.json +189 -0
  471. package/src/surfaces/welcome.json +571 -0
  472. package/src/surfaces/welcome.ts +338 -0
  473. package/src/tabs/project-config.ts +111 -21
  474. package/src/tabs/tab.ts +52 -1
  475. package/src/types.ts +22 -0
  476. package/src/ui/ai-credentials-form.ts +104 -100
  477. package/src/ui/ai-managed-connect.ts +54 -36
  478. package/src/ui/ai-model-picker.ts +75 -47
  479. package/src/ui/cf-account-picker.ts +76 -141
  480. package/src/ui/color-selector.ts +80 -301
  481. package/src/ui/dynamic-slot.ts +43 -283
  482. package/src/ui/expression-editor.ts +797 -576
  483. package/src/ui/field-input.ts +8 -181
  484. package/src/ui/form-controls.ts +838 -366
  485. package/src/ui/formula-chips.ts +80 -85
  486. package/src/ui/kit.ts +33 -0
  487. package/src/ui/layers.ts +296 -593
  488. package/src/ui/media-picker.ts +203 -284
  489. package/src/ui/panel-resize.ts +251 -64
  490. package/src/ui/popover-surface.ts +153 -0
  491. package/src/ui/progress-modal.ts +22 -60
  492. package/src/ui/regions.ts +13 -7
  493. package/src/ui/schema-form.ts +906 -440
  494. package/src/ui/surface.ts +122 -0
  495. package/src/ui/unit-selector.ts +15 -131
  496. package/src/ui/value-source.ts +14 -0
  497. package/src/ui/virtual-window.ts +88 -9
  498. package/src/utils/canvas-media.ts +72 -0
  499. package/src/utils/edit-display.ts +7 -2
  500. package/src/utils/element-selectors.ts +69 -0
  501. package/src/utils/link-target.ts +2 -2
  502. package/src/utils/studio-utils.ts +0 -10
  503. package/src/view.ts +15 -0
  504. package/src/workspace/pane-derive.ts +36 -14
  505. package/src/workspace/workspace.ts +75 -6
  506. package/styles/canvas.css +72 -467
  507. package/styles/forced-colors.css +48 -82
  508. package/styles/forced-colors.json +41 -0
  509. package/styles/inspector.css +2 -1301
  510. package/styles/overlays.css +96 -2823
  511. package/styles/panels.css +6 -1423
  512. package/styles/shell-frame.css +272 -0
  513. package/styles/shell-frame.json +227 -0
  514. package/styles/shell.css +0 -1568
  515. package/styles/tokens.css +65 -136
  516. package/styles/tokens.json +84 -0
  517. package/dist/chunks/Overlay.dev-etqjwyf9.js +0 -23
  518. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  519. package/dist/chunks/cf-account-picker-en86v7x7.js +0 -163
  520. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  521. package/dist/chunks/components-zmx10t62.js +0 -21
  522. package/dist/chunks/content-source-48xg86wj.js +0 -49
  523. package/dist/chunks/convert-to-repeater-43tfn7cs.js +0 -268
  524. package/dist/chunks/editor-cptq5jp1.js +0 -37
  525. package/dist/chunks/entry-commands-e63f1xc0.js +0 -46
  526. package/dist/chunks/extension-sections-txv08xxg.js +0 -311
  527. package/dist/chunks/file-ops-wbh4hhsx.js +0 -48
  528. package/dist/chunks/files-3kfkwhk4.js +0 -93
  529. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  530. package/dist/chunks/focus-trap.esm-9t2drp0g.js +0 -1025
  531. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  532. package/dist/chunks/format-host-w16q81tf.js +0 -43
  533. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  534. package/dist/chunks/git-panel-532whr1y.js +0 -59
  535. package/dist/chunks/index-zqxmqxmh.js +0 -109
  536. package/dist/chunks/jx-validate-8er6gbxy.js +0 -19
  537. package/dist/chunks/layers-panel-07hm7g5j.js +0 -67
  538. package/dist/chunks/layers-q75tj2mf.js +0 -45
  539. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  540. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  541. package/dist/chunks/notify-yjm79n4s.js +0 -30
  542. package/dist/chunks/parse-24d0gay3.js +0 -19
  543. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  544. package/dist/chunks/publish-panel-v9st96ja.js +0 -29
  545. package/dist/chunks/quick-search-zccjp6gv.js +0 -66
  546. package/dist/chunks/references-3qx8fkyp.js +0 -29
  547. package/dist/chunks/right-panel-vm3b6kwy.js +0 -46
  548. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  549. package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +0 -18
  550. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  551. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  552. package/dist/chunks/sp-tooltip.dev-4sastdnw.js +0 -15
  553. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  554. package/dist/chunks/studio-0a5qrh01.js +0 -3
  555. package/dist/chunks/studio-0bq6eh7v.js +0 -12
  556. package/dist/chunks/studio-18j3bmcz.js +0 -14
  557. package/dist/chunks/studio-1ngbejft.js +0 -181
  558. package/dist/chunks/studio-4b5z1x43.js +0 -424
  559. package/dist/chunks/studio-4n2b5gzb.js +0 -357
  560. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  561. package/dist/chunks/studio-5fx3g9jg.js +0 -4325
  562. package/dist/chunks/studio-5myknm0a.js +0 -1903
  563. package/dist/chunks/studio-7afd21nw.js +0 -67
  564. package/dist/chunks/studio-7nte2hj4.js +0 -613
  565. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  566. package/dist/chunks/studio-8q517dfr.js +0 -24
  567. package/dist/chunks/studio-950k0dx6.js +0 -6939
  568. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  569. package/dist/chunks/studio-a0tswy0w.js +0 -58
  570. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  571. package/dist/chunks/studio-bgxt93ga.js +0 -62
  572. package/dist/chunks/studio-cmb03bg5.js +0 -13890
  573. package/dist/chunks/studio-d1ks410h.js +0 -175
  574. package/dist/chunks/studio-ef49pnzx.js +0 -387
  575. package/dist/chunks/studio-eqq1w638.js +0 -113
  576. package/dist/chunks/studio-ew0djmhg.js +0 -341
  577. package/dist/chunks/studio-gfgb8pe6.js +0 -1652
  578. package/dist/chunks/studio-h4rxscfc.js +0 -10
  579. package/dist/chunks/studio-jc994dnr.js +0 -1066
  580. package/dist/chunks/studio-kyh9avvv.js +0 -28
  581. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  582. package/dist/chunks/studio-mtfnaqs9.js +0 -659
  583. package/dist/chunks/studio-n6j9t10q.js +0 -318
  584. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  585. package/dist/chunks/studio-qcy05dp8.js +0 -1743
  586. package/dist/chunks/studio-qq6jym04.js +0 -53
  587. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  588. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  589. package/dist/chunks/studio-t7qb9db8.js +0 -665
  590. package/dist/chunks/studio-tmc5emrw.js +0 -8
  591. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  592. package/dist/chunks/studio-zczps70q.js +0 -378
  593. package/dist/chunks/studio-zqazsct2.js +0 -1823
  594. package/dist/chunks/workspace-fjx52ryv.js +0 -89
  595. package/src/panels/activity-bar.ts +0 -251
  596. package/src/panels/panel-scheduler.ts +0 -219
  597. package/src/panels/style-inputs.ts +0 -237
  598. package/src/panels/target-line.ts +0 -274
  599. package/src/panels/welcome-screen.ts +0 -346
  600. package/src/ui/button-group.ts +0 -102
  601. package/src/ui/choice-field.ts +0 -72
  602. package/src/ui/field-row.ts +0 -249
  603. package/src/ui/formula-palette.ts +0 -213
  604. package/src/ui/icons.ts +0 -52
  605. package/src/ui/jx-theme.ts +0 -130
  606. package/src/ui/spectrum.ts +0 -340
  607. package/src/ui/value-selector.ts +0 -174
  608. package/src/ui/widgets.ts +0 -172
  609. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  610. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  611. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  612. /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
@@ -0,0 +1,538 @@
1
+ /**
2
+ * Ai-command-tools.ts — the assistant's tools that ARE command records.
3
+ *
4
+ * A `ToolRegistry` that is a VIEW over this window's active command registry, in the idiom of
5
+ * `services/automation.ts`'s `scriptableCommands()`: nothing is registered here, ever. Every call to
6
+ * `listForLLM()` enumerates the records that carry an `aiTool` projection and builds one function
7
+ * schema per record whose `parameters` is the record's own `args` object — by reference, so a
8
+ * `derivedEnumProperty` getter serialises live on every agent-loop round — whose `description` is
9
+ * the record's, and which is advertised exactly while `registry.isEnabled(id)` holds. `execute` is
10
+ * `registry.run(id, args)`.
11
+ *
12
+ * **Why a view and not a registration.** `const assistant = createDocumentAssistant()` runs at
13
+ * module load of `panels/ai-panel.ts`, before the bootstrap composes the registry, so a
14
+ * registration step would have to import `app-commands.ts` (every command module into the
15
+ * assistant's import graph) and read `report` from a record built with `noopCommandDeps` — a
16
+ * second instance of every record, whose closures are not the app's. A view has neither problem,
17
+ * and it cannot be dormant: issue 273 was forty-seven declarations that reached the assistant from
18
+ * none of them, because each waited on a hand-registered tool nobody wrote. There is no
19
+ * registration step between `aiTool` and the tool, so there is nothing to omit.
20
+ *
21
+ * **What the model reads.** A refusal is the person's own sentence: `CommandUnavailableError.message`
22
+ * IS `refusalSentence`, and a `RangeError` from `coerceArgs` (which `registry.run` applies for
23
+ * every caller) or from inside `run` already names the value and the declared list. Both pass
24
+ * through untouched. There is deliberately no pre-check with `refusalMessage` — `run` refuses with
25
+ * the same sentence, and a second call site for one predicate is precisely the divergence
26
+ * `specs/studio-ui-guidelines.md` §12.4 is about. And because this module owns `execute`,
27
+ * `@jxsuite/ai`'s `Tool "<name>" execution error:` prefix never wraps a refusal.
28
+ *
29
+ * **The write witness.** A record with `undo: "document"` is held to having written: `transactDoc`
30
+ * replaces the document's root reference on every applied transaction (`tabs/transact.ts`), so an
31
+ * unchanged reference after `run` means the collab freeze refused it, or `run` returned early, and
32
+ * the model is told "changed nothing" rather than congratulated. This is what closes the
33
+ * phantom-success finding for every bridged document write, not just the one tool it was found on.
34
+ *
35
+ * **The project witness** is the same comparison over `project.json`. Every configuration write is
36
+ * a transaction on the configuration document (`tabs/project-config.ts`), whose bind effect keeps
37
+ * `projectState.projectConfig` equal to `toRaw(document.doc.document)` — so a record with `undo:
38
+ * "project"` that left that reference alone wrote nothing, whatever its report says. The ledger
39
+ * then files nothing (`wrote: []`, mechanically, for every project record), and a report that
40
+ * named no `wrote` of its own — one with no latch to know it was a no-op — has its sentence
41
+ * replaced by "changed nothing", because "Wrote project.json" over an untouched file is the
42
+ * phantom the ledger exists to keep out. A record whose report answered `wrote: []` itself is one
43
+ * that KNEW, and its sentence ("already enabled") is the one the witness cannot write. That is why
44
+ * `add_project_locale` keeps its latch: the sentence, not the ledger, is what the latch is for.
45
+ *
46
+ * **A tool with nothing it could be called with is withheld.** A `derivedEnumProperty` on a
47
+ * REQUIRED argument serialises `enum: []` when the list behind it is empty — `enable_extension`
48
+ * with no catalogue — and `@jxsuite/ai`'s validator tolerates that only because every projected
49
+ * tool is `strict: false`. The record's gate cannot see its own argument list, so the bridge reads
50
+ * it: an enabled record whose required enum is empty is not advertised this round, and comes back
51
+ * the round the list does. `getDefinition` still answers, so a call the model makes anyway meets
52
+ * the coercion's own refusal (`is not declared — declared: none`) rather than `Unknown tool`.
53
+ *
54
+ * **`validate()` is a no-op, on purpose.** `@jxsuite/ai`'s validator never checks `enum` and treats
55
+ * a required `null` as missing (`packages/ai/src/tools.ts`), which would refuse `select_node
56
+ * { path: null }`. The registry's coercion is the single validator, so every projected tool is
57
+ * `strict: false`.
58
+ *
59
+ * @license MIT
60
+ */
61
+
62
+ import { toolError } from "@jxsuite/ai/tools";
63
+ import type { ToolDefinition, ToolRegistry, ToolResult } from "@jxsuite/ai/tools";
64
+ import { activeRegistry } from "../commands/active-registry";
65
+ import { argsSchema } from "../commands/command-args";
66
+ import { inCanvas } from "../commands/context";
67
+ import { toRaw } from "../reactivity";
68
+ import { projectState } from "../state";
69
+ import { recordWrite } from "./ai-writes";
70
+ import { reportDocumentWrite, snapshotBeforeWrite } from "./ai-write-report";
71
+ import type { WriteReportDeps, WriteSnapshot } from "./ai-write-report";
72
+ import type { CommandContext } from "../commands/context";
73
+ import type { AiToolReport, AnyCommand, CommandRegistry } from "../commands/registry";
74
+ import type { Tab } from "../tabs/tab";
75
+
76
+ /**
77
+ * The record a selection-level projection composes through.
78
+ *
79
+ * The model addresses nodes by path, so a selection verb's tool takes `paths` and the bridge runs
80
+ * this selector first. "Act on whatever is selected" would be a verb over state the model cannot
81
+ * observe — the same objection `specs/studio.md` §13.5 raises against a `toggle*` id.
82
+ */
83
+ export const SELECTOR = "selection.setPaths";
84
+
85
+ /** What the bridge needs that a command record cannot know: the tab, and the write reporter's deps. */
86
+ export interface CommandToolDeps extends WriteReportDeps {
87
+ /**
88
+ * The active tab — the document a `undo: "document"` record wrote, for the witness and the
89
+ * ledger.
90
+ */
91
+ getTab: () => Tab | null;
92
+ }
93
+
94
+ /** Schema for a record that declares no `args`: an empty object, so the wire shape is uniform. */
95
+ const EMPTY_ARGS = argsSchema({});
96
+
97
+ /** The loosely-typed view of a record's `args` this module reads. */
98
+ interface ArgsShape {
99
+ properties?: Record<string, { enum?: unknown }>;
100
+ required?: readonly string[];
101
+ }
102
+
103
+ /**
104
+ * Whether a required argument's choice list is empty right now.
105
+ *
106
+ * Reading `enum` is what serialises a `derivedEnumProperty` — the getter runs here exactly as it
107
+ * runs on the wire — so this is the same answer the model would have been shown. Only a REQUIRED
108
+ * property counts: an optional enum that is empty is an argument the model can leave out.
109
+ */
110
+ function hasEmptyRequiredEnum(args: object | undefined): boolean {
111
+ const shape = (args ?? EMPTY_ARGS) as ArgsShape;
112
+ return (shape.required ?? []).some((key) => {
113
+ const declared = shape.properties?.[key]?.enum;
114
+ return Array.isArray(declared) && declared.length === 0;
115
+ });
116
+ }
117
+
118
+ /**
119
+ * The selector's own `paths` property object, taken BY REFERENCE from the live record so the
120
+ * description the model reads is the selector's. `undefined` when the selector is not registered,
121
+ * in which case no selection-level record can be composed and none is projected.
122
+ */
123
+ function pathsProperty(registry: CommandRegistry): object | undefined {
124
+ const args = registry.get(SELECTOR)?.args as ArgsShape | undefined;
125
+ return args?.properties?.paths;
126
+ }
127
+
128
+ /**
129
+ * A selection-level record's parameters: the selector's `paths` in front, REQUIRED, then the
130
+ * record's own properties. Merging the record's after the selector's is what lets a future
131
+ * selection verb with an argument of its own compose without a rule change — and `register()`
132
+ * refuses a selection-level record that declares `paths` itself, so the two cannot collide.
133
+ */
134
+ function withPaths(paths: object, args: object | undefined): object {
135
+ const own = (args ?? EMPTY_ARGS) as ArgsShape;
136
+ return {
137
+ additionalProperties: false,
138
+ properties: { paths, ...own.properties },
139
+ required: ["paths", ...(own.required ?? [])],
140
+ type: "object",
141
+ };
142
+ }
143
+
144
+ /**
145
+ * The tail every projected description carries, so a record says neither in its own sentence.
146
+ *
147
+ * `undo` names what ⌘Z reaches; `destructive` is the same flag the menus derive the danger styling
148
+ * from. A record with no `undo` is a read or a navigation, and says nothing.
149
+ */
150
+ function undoSuffix(command: AnyCommand): string {
151
+ const undo =
152
+ command.undo === "document"
153
+ ? " Undo: document."
154
+ : command.undo === "project"
155
+ ? " Undo: project."
156
+ : command.undo === "none"
157
+ ? " Not undoable."
158
+ : "";
159
+ return `${undo}${command.destructive ? " Destructive." : ""}`;
160
+ }
161
+
162
+ /**
163
+ * Whether a selection-level projection can be composed and honoured right now: a document tree is
164
+ * on the canvas (`inCanvas`, the predicate `hasSelection` is built from — read, not respelled) and
165
+ * the selector is usable, which is "a document is open". The `count > 0` conjunct of the verb's own
166
+ * `when` is what the bridge satisfies itself by running the selector.
167
+ */
168
+ function selectionAdvertised(registry: CommandRegistry): boolean {
169
+ return (
170
+ inCanvas(registry.context()) &&
171
+ registry.get(SELECTOR) !== undefined &&
172
+ registry.isEnabled(SELECTOR)
173
+ );
174
+ }
175
+
176
+ /**
177
+ * Whether one record's tool is advertised this round. For a project- or document-level record it is
178
+ * the record's own gate, evaluated as the palette evaluates it — a module-state `enablement`
179
+ * closure included. Selection-level records are the one derived case, above. And a record the gate
180
+ * admits is still withheld while a required argument has an empty choice list: there is nothing it
181
+ * could be called with, and a tool advertised with `enum: []` costs a round to discover that.
182
+ */
183
+ function advertised(registry: CommandRegistry, command: AnyCommand): boolean {
184
+ const open =
185
+ command.level === "selection" ? selectionAdvertised(registry) : registry.isEnabled(command.id);
186
+ return open && !hasEmptyRequiredEnum(command.args);
187
+ }
188
+
189
+ /** Every record carrying a projection, enabled or not. */
190
+ function projected(registry: CommandRegistry): AnyCommand[] {
191
+ return registry.list().filter((command) => command.aiTool !== undefined);
192
+ }
193
+
194
+ /**
195
+ * The definition one record projects, or `undefined` for a selection-level record when the selector
196
+ * it composes through is not registered.
197
+ */
198
+ function definitionOf(
199
+ registry: CommandRegistry,
200
+ command: AnyCommand,
201
+ execute: (name: string, args: object) => Promise<ToolResult>,
202
+ ): ToolDefinition | undefined {
203
+ const tool = command.aiTool!;
204
+ let parameters: object;
205
+ if (command.level === "selection") {
206
+ const paths = pathsProperty(registry);
207
+ if (paths === undefined) {
208
+ return undefined;
209
+ }
210
+ parameters = withPaths(paths, command.args);
211
+ } else {
212
+ parameters = command.args ?? EMPTY_ARGS;
213
+ }
214
+ return {
215
+ name: tool.name,
216
+ description: `${tool.description}${undoSuffix(command)}`,
217
+ parameters: parameters as ToolDefinition["parameters"],
218
+ strict: false,
219
+ llmStrict: false,
220
+ execute: (args) => execute(tool.name, args),
221
+ };
222
+ }
223
+
224
+ /**
225
+ * Pure: the definitions a given registry projects RIGHT NOW (advertised = the record's gate).
226
+ *
227
+ * Read by `listForLLM()` and by {@link commandToolBlurbs} both, so the prompt advertises exactly
228
+ * what the gate will honour — one function, not two that agree until someone edits one.
229
+ *
230
+ * @param {CommandRegistry} registry
231
+ * @param {(name: string, args: object) => Promise<ToolResult>} [execute] What each definition's
232
+ * `execute` calls. Defaults to a refusal, so a caller that only reads definitions cannot run
233
+ * one.
234
+ * @returns {ToolDefinition[]}
235
+ */
236
+ export function advertisedCommandTools(
237
+ registry: CommandRegistry,
238
+ execute: (name: string, args: object) => Promise<ToolResult> = async (name) =>
239
+ toolError(`Tool "${name}" was listed without an executor.`),
240
+ ): ToolDefinition[] {
241
+ const definitions: ToolDefinition[] = [];
242
+ for (const command of projected(registry)) {
243
+ if (!advertised(registry, command)) {
244
+ continue;
245
+ }
246
+ const definition = definitionOf(registry, command, execute);
247
+ if (definition) {
248
+ definitions.push(definition);
249
+ }
250
+ }
251
+ return definitions;
252
+ }
253
+
254
+ /** The parameter list a prompt blurb prints: `a, b?` — required names bare, optional ones marked. */
255
+ function signatureOf(parameters: object): string {
256
+ const shape = parameters as ArgsShape;
257
+ const required = new Set(shape.required);
258
+ return Object.keys(shape.properties ?? {})
259
+ .map((key) => (required.has(key) ? key : `${key}?`))
260
+ .join(", ");
261
+ }
262
+
263
+ /**
264
+ * Pure: the prompt lines for the definitions a registry projects right now, in the hand tools' own
265
+ * blurb shape: `name(a, b?) — description`. `null` (no registry composed yet) is no lines.
266
+ *
267
+ * Why `isEnabled` rather than `isVisible` with a "(not right now)" line: the prompt's invariant is
268
+ * "advertises exactly what the gate will honour", and with the kept records there is no steady
269
+ * state in which a projected record is visible and disabled, so the line would be empty in practice
270
+ * and cost a wasted round when it was not. If a future record wants the palette's "why can't I"
271
+ * answer in the prompt, this is the one function to extend.
272
+ *
273
+ * @param {CommandRegistry | null} registry
274
+ * @returns {string[]}
275
+ */
276
+ export function commandToolBlurbs(registry: CommandRegistry | null): string[] {
277
+ if (!registry) {
278
+ return [];
279
+ }
280
+ return advertisedCommandTools(registry).map(
281
+ (definition) =>
282
+ `${definition.name}(${signatureOf(definition.parameters)}) — ${definition.description}`,
283
+ );
284
+ }
285
+
286
+ /** A `report` return, normalised: a bare string is a summary alone. */
287
+ function normaliseReport(report: string | AiToolReport): AiToolReport {
288
+ return typeof report === "string" ? { summary: report } : report;
289
+ }
290
+
291
+ /**
292
+ * The configuration object the app is live on, unwrapped, or `null` before a project has one.
293
+ *
294
+ * The same read `tabs/project-config.ts`'s `liveConfig()` makes: `projectState.projectConfig` is
295
+ * held to `toRaw(document.doc.document)` by the bind effect, so a `transactDoc` on the
296
+ * configuration document is a new reference here — and an unchanged reference is a run that never
297
+ * transacted, however the record's report reads.
298
+ */
299
+ function projectConfigRef(): object | null {
300
+ const config = projectState?.projectConfig;
301
+ return config ? toRaw(config as unknown as object) : null;
302
+ }
303
+
304
+ /**
305
+ * The ledger paths a record's write defaults to when `report` names none, by undo scope. `"none"`
306
+ * has no default on purpose — see {@link AiToolReport.wrote}.
307
+ */
308
+ function defaultPaths(command: AnyCommand, tab: Tab | null): string[] {
309
+ if (command.undo === "document") {
310
+ return [tab?.documentPath ?? "(untitled)"];
311
+ }
312
+ if (command.undo === "project") {
313
+ return ["project.json"];
314
+ }
315
+ return ["(unknown file)"];
316
+ }
317
+
318
+ /**
319
+ * File a projected run in the "Changed N files" ledger, by undo scope.
320
+ *
321
+ * No `undo` is a read or a navigation and records nothing. `disk` is `undo === "none"`, because
322
+ * `undo: "project"` IS a transaction ⌘Z reaches and the ledger's flag means "unreachable by undo".
323
+ * An EMPTY `wrote` is a run that changed nothing — an idempotent verb asked for a state it already
324
+ * had — and files nothing, because the ledger names files that changed; `undefined` is a report
325
+ * that named none and takes the record's defaults.
326
+ */
327
+ function fileLedger(command: AnyCommand, tab: Tab | null, wrote?: readonly string[]): void {
328
+ if (command.undo === undefined) {
329
+ return;
330
+ }
331
+ const disk = command.undo === "none";
332
+ for (const path of wrote ?? defaultPaths(command, tab)) {
333
+ recordWrite({ disk, ok: true, path, tool: command.title });
334
+ }
335
+ }
336
+
337
+ /**
338
+ * A ToolRegistry whose tools are the active registry's `aiTool` records. Nothing is registered.
339
+ *
340
+ * @param {CommandToolDeps} deps
341
+ * @returns {ToolRegistry}
342
+ */
343
+ export function createCommandToolRegistry(deps: CommandToolDeps): ToolRegistry {
344
+ /** The record projecting `name`, enabled or not — so `execute` can reach a refusal. */
345
+ function commandFor(name: string): AnyCommand | undefined {
346
+ return activeRegistry()
347
+ ?.list()
348
+ .find((command) => command.aiTool?.name === name);
349
+ }
350
+
351
+ /**
352
+ * Run one projected record as the agent — the whole of §3 of the design.
353
+ *
354
+ * @param {string} name
355
+ * @param {object} received
356
+ * @returns {Promise<ToolResult>}
357
+ */
358
+ async function execute(name: string, received: object): Promise<ToolResult> {
359
+ const registry = activeRegistry();
360
+ const command = commandFor(name);
361
+ if (!registry || !command) {
362
+ /* Two absences, one shape. A window with no registry is answered in today's wording; a name
363
+ no record projects is `@jxsuite/ai`'s own `Unknown tool` sentence. */
364
+ return registry
365
+ ? toolError(`Unknown tool: "${name}"`)
366
+ : { error: `Cannot run "${name}" — this window has no command registry.`, success: false };
367
+ }
368
+ const tool = command.aiTool!;
369
+ const args = received as Record<string, unknown>;
370
+
371
+ /* The witness and the snapshot, only for a record that writes the document: `rootBefore` is
372
+ what `transactDoc` replaces, and the snapshot is what the verdict compares against. */
373
+ const tab = command.undo === "document" ? deps.getTab() : null;
374
+ const rootBefore = tab ? toRaw(tab.doc.document) : null;
375
+ /* The project witness's half: the configuration object the chokepoint holds, which every
376
+ applied `project.json` transaction replaces. Read for `undo: "project"` records only — the
377
+ comparison is meaningless for a record that does not claim the file. */
378
+ const configBefore = command.undo === "project" ? projectConfigRef() : null;
379
+ let snapshot: WriteSnapshot | null = null;
380
+ let before: CommandContext;
381
+ try {
382
+ if (tab) {
383
+ snapshot = await snapshotBeforeWrite(tab, deps);
384
+ }
385
+ if (command.level === "selection") {
386
+ /* The selector first, with its own gate and its own argument refusal ("addresses no
387
+ node", "expected an array of document paths"); then the verb, against the selection the
388
+ selector made. Both steps are records; the bridge holds no predicate of its own. On a
389
+ refusal at the second step the selection stays where the selector put it — the honest
390
+ trace of what the agent attempted, and restoring it would be a second write inside a
391
+ refusal path. */
392
+ const { paths, ...rest } = args;
393
+ await registry.run(SELECTOR, { paths });
394
+ before = registry.context();
395
+ await registry.run(command.id, rest);
396
+ } else {
397
+ before = registry.context();
398
+ await registry.run(command.id, args);
399
+ }
400
+ } catch (error) {
401
+ return { error: error instanceof Error ? error.message : String(error), success: false };
402
+ }
403
+
404
+ if (tab && toRaw(tab.doc.document) === rootBefore) {
405
+ const frozen = registry.context().collab.sourceCanonical
406
+ ? " A collaborator is editing its source, so structural edits are paused."
407
+ : "";
408
+ return {
409
+ error: `${command.title} changed nothing: the document is exactly as it was.${frozen}`,
410
+ success: false,
411
+ };
412
+ }
413
+
414
+ /* The project witness's verdict, decided before the report so a report that throws is filed
415
+ against it too. Unlike the document witness this is not a refusal: an idempotent project verb
416
+ asked for a state it already had is an ordinary answer, and the record's own sentence may
417
+ say why. What the witness owns is the LEDGER — nothing landed, so nothing is filed. */
418
+ const projectUnchanged = command.undo === "project" && projectConfigRef() === configBefore;
419
+
420
+ const after = registry.context();
421
+ let report: AiToolReport;
422
+ try {
423
+ report = normaliseReport(tool.report({ after, args: args as never, before }));
424
+ } catch (error) {
425
+ /* `run` has resolved, so the write HAPPENED; a report that throws must not make it vanish.
426
+ Left to the loop, the throw would be labelled "Failed to parse arguments" and the ledger
427
+ would never be filed. So the ledger is filed from `undo`'s defaults — the report that would
428
+ have named the paths is the thing that failed — and the model is told both halves. */
429
+ fileLedger(command, tab, projectUnchanged ? [] : undefined);
430
+ const message = error instanceof Error ? error.message : String(error);
431
+ return { error: `${command.title} ran, but its report failed: ${message}`, success: false };
432
+ }
433
+
434
+ let { summary, wrote } = report;
435
+ if (projectUnchanged) {
436
+ /* The ledger files nothing whatever the report named. A report that did not itself know it
437
+ was a no-op has its sentence replaced — a claim of a write over an untouched file is
438
+ exactly the phantom this exists to catch. A report that answered `wrote: []` knew, and its
439
+ sentence is kept: it says WHY nothing changed, which the witness cannot. */
440
+ wrote = [];
441
+ if (report.wrote === undefined || report.wrote.length > 0) {
442
+ summary = `${command.title} changed nothing: project.json is exactly as it was.`;
443
+ }
444
+ }
445
+ fileLedger(command, tab, wrote);
446
+ if (tab && snapshot) {
447
+ const verdict = await reportDocumentWrite(tab, snapshot, summary, deps);
448
+ if (!verdict.success) {
449
+ return verdict;
450
+ }
451
+ /* A success verdict may have appended the token hints; the report's sentence is kept. */
452
+ summary = verdict.summary ?? summary;
453
+ }
454
+ return {
455
+ success: true,
456
+ summary,
457
+ ...(report.data === undefined ? {} : { data: report.data }),
458
+ };
459
+ }
460
+
461
+ return {
462
+ register() {
463
+ throw new Error(
464
+ "command tools are a view over the registry; declare aiTool on the record instead",
465
+ );
466
+ },
467
+ list() {
468
+ const registry = activeRegistry();
469
+ return registry ? advertisedCommandTools(registry, execute) : [];
470
+ },
471
+ listForLLM() {
472
+ return this.list().map((definition) => ({
473
+ type: "function",
474
+ function: {
475
+ name: definition.name,
476
+ description: definition.description,
477
+ parameters: definition.parameters,
478
+ },
479
+ }));
480
+ },
481
+ getDefinition(name) {
482
+ const registry = activeRegistry();
483
+ const command = commandFor(name);
484
+ return registry && command ? definitionOf(registry, command, execute) : undefined;
485
+ },
486
+ validate() {
487
+ return { valid: true };
488
+ },
489
+ execute,
490
+ };
491
+ }
492
+
493
+ /**
494
+ * Union of two registries for the loop: hand tools gated by tier, command tools gated by the
495
+ * record.
496
+ *
497
+ * `list`/`listForLLM` concatenate (hand first); `getDefinition`/`validate`/`execute` go to
498
+ * whichever side has the definition, hand first; an unknown name answers `Unknown tool: "<name>"`
499
+ * as `@jxsuite/ai` does; `register` goes to `hand`. A name on both sides is a defect the parity
500
+ * test in `tests/ai-system-prompt.test.ts` catches; the composite's hand-first order is not a
501
+ * feature anyone may rely on.
502
+ *
503
+ * @param {ToolRegistry} hand
504
+ * @param {ToolRegistry} commands
505
+ * @returns {ToolRegistry}
506
+ */
507
+ export function composeToolRegistries(hand: ToolRegistry, commands: ToolRegistry): ToolRegistry {
508
+ function sideOf(name: string): ToolRegistry | undefined {
509
+ if (hand.getDefinition(name)) {
510
+ return hand;
511
+ }
512
+ return commands.getDefinition(name) ? commands : undefined;
513
+ }
514
+ return {
515
+ register(tool) {
516
+ hand.register(tool);
517
+ },
518
+ list() {
519
+ return [...hand.list(), ...commands.list()];
520
+ },
521
+ listForLLM() {
522
+ return [...hand.listForLLM(), ...commands.listForLLM()];
523
+ },
524
+ getDefinition(name) {
525
+ return sideOf(name)?.getDefinition(name);
526
+ },
527
+ validate(name, args) {
528
+ const side = sideOf(name);
529
+ return side
530
+ ? side.validate(name, args)
531
+ : { valid: false, errors: [`Unknown tool: "${name}"`] };
532
+ },
533
+ async execute(name, args) {
534
+ const side = sideOf(name);
535
+ return side ? side.execute(name, args) : toolError(`Unknown tool: "${name}"`);
536
+ },
537
+ };
538
+ }
@@ -115,8 +115,14 @@ export interface ProjectToolsCtx {
115
115
  * tab happened to be re-read from disk afterwards ({@link ProjectToolsCtx.reloadTab}); that
116
116
  * re-read is gone, because a second parse of `project.json` is the very rival object the
117
117
  * configuration document exists to prevent.
118
+ *
119
+ * `text` is the bytes that reached the file, of which `config` is the parse. The document keeps a
120
+ * layout record for the file it holds (§9.4), and the assistant's write replaces the file — so
121
+ * the record has to travel with the write, or the next settings commit re-lays the file the model
122
+ * just formatted with the record of the file it had read before (issue 331). Handing the text
123
+ * over is what lets the document derive that record without reading the file back.
118
124
  */
119
- onProjectConfigWritten?: (config: ProjectConfig) => void | Promise<void>;
125
+ onProjectConfigWritten?: (config: ProjectConfig, text: string) => void | Promise<void>;
120
126
  }
121
127
 
122
128
  /**
@@ -399,7 +405,7 @@ export function registerProjectTools(
399
405
  that tab, which is the split the adoption just closed. Every other path is a plain file
400
406
  and its tab has to be told from disk. */
401
407
  if (projectConfig) {
402
- await onProjectConfigWritten?.(projectConfig);
408
+ await onProjectConfigWritten?.(projectConfig, content);
403
409
  } else if (openTab) {
404
410
  await reloadTab(relPath);
405
411
  }
@@ -45,6 +45,12 @@ export interface PersistedMessage {
45
45
  id?: string;
46
46
  role: string;
47
47
  content: string;
48
+ /**
49
+ * A thinking model's chain-of-thought for the turn. Persisted because the provider requires it
50
+ * back: a restored DeepSeek conversation whose reasoning was dropped on the way to storage is one
51
+ * the next send cannot replay (see `@jxsuite/ai`'s `toMessagesArray`).
52
+ */
53
+ reasoningContent?: string;
48
54
  toolCalls?: unknown[];
49
55
  toolCallId?: string;
50
56
  timestamp?: number;