@jxsuite/studio 6.1.1 → 6.1.2

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 (637) hide show
  1. package/dist/chunks/{2020-va2wwra4.js → 2020-f2gkpy8d.js} +3 -3
  2. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  3. package/dist/chunks/adapter-4912g339.js +4 -0
  4. package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
  5. package/dist/chunks/cf-settings-br6105tr.js +4 -0
  6. package/dist/chunks/color-28ksk2qm.js +4 -0
  7. package/dist/chunks/color-area-0fj8a4ga.js +4 -0
  8. package/dist/chunks/color-field-xch8kx2g.js +4 -0
  9. package/dist/chunks/color-slider-jxd8v350.js +4 -0
  10. package/dist/chunks/combobox-p0efwjke.js +4 -0
  11. package/dist/chunks/components-db68vsn7.js +4 -0
  12. package/dist/chunks/content-source-1449qesq.js +4 -0
  13. package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
  14. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  15. package/dist/chunks/editor-x9jn86a7.js +4 -0
  16. package/dist/chunks/entry-commands-may24cpt.js +4 -0
  17. package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
  18. package/dist/chunks/file-ops-x9v54pcj.js +4 -0
  19. package/dist/chunks/files-j3knqf0s.js +4 -0
  20. package/dist/chunks/format-host-tyre2trb.js +4 -0
  21. package/dist/chunks/fs-events-64ma9htc.js +4 -0
  22. package/dist/chunks/git-panel-84ps5dex.js +4 -0
  23. package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
  24. package/dist/chunks/icons-pnfz478q.js +4 -0
  25. package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
  26. package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
  27. package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
  28. package/dist/chunks/iframe-entry-zap785cw.js +5 -0
  29. package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
  30. package/dist/chunks/index-b8xw3vy9.js +4 -0
  31. package/dist/chunks/{index-2veqmnhr.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-8nbvs12s.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/{jsonMode-s8kt9dsj.js → jsonMode-w15cmrcm.js} +8 -8
  34. package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
  35. package/dist/chunks/layers-h4xp1pss.js +4 -0
  36. package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
  37. package/dist/chunks/listbox-e74qjyq6.js +4 -0
  38. package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
  39. package/dist/chunks/media-picker-2cweexc5.js +4 -0
  40. package/dist/chunks/menu-n6yzswmy.js +4 -0
  41. package/dist/chunks/menu-ynw13y0s.js +4 -0
  42. package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
  43. package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
  44. package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
  45. package/dist/chunks/notify-cj5zbrs2.js +4 -0
  46. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  47. package/dist/chunks/parse-b7ddhr8m.js +4 -0
  48. package/dist/chunks/platform-3dfws9js.js +4 -0
  49. package/dist/chunks/popover-jt2gxmzs.js +4 -0
  50. package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
  51. package/dist/chunks/quick-search-0dajrwqg.js +4 -0
  52. package/dist/chunks/references-49qgt404.js +4 -0
  53. package/dist/chunks/right-panel-jm1bwe53.js +4 -0
  54. package/dist/chunks/section-registry-6kwc4fky.js +4 -0
  55. package/dist/chunks/select-rzds841e.js +4 -0
  56. package/dist/chunks/split-n2gfpm5m.js +4 -0
  57. package/dist/chunks/{studio-1q1sh2ax.js → studio-0q988f9w.js} +3 -3
  58. package/dist/chunks/studio-0rt52vpq.js +5 -0
  59. package/dist/chunks/studio-18vgbhs5.js +5 -0
  60. package/dist/chunks/{studio-h46vtzk8.js → studio-1fxkaaea.js} +4 -4
  61. package/dist/chunks/studio-24mccdrj.js +5 -0
  62. package/dist/chunks/studio-2eh507zk.js +9 -0
  63. package/dist/chunks/studio-2hcbccfv.js +5 -0
  64. package/dist/chunks/studio-2j1cb95x.js +5 -0
  65. package/dist/chunks/studio-2jbs3rxv.js +5 -0
  66. package/dist/chunks/{studio-rv11kfwa.js → studio-485046te.js} +7 -7
  67. package/dist/chunks/studio-4h8k4dw9.js +5 -0
  68. package/dist/chunks/studio-5f6n18kx.js +5 -0
  69. package/dist/chunks/studio-5gthpky6.js +5 -0
  70. package/dist/chunks/studio-5ve6bbep.js +5 -0
  71. package/dist/chunks/studio-6ep3js6b.js +9 -0
  72. package/dist/chunks/studio-6wkmf3wz.js +9 -0
  73. package/dist/chunks/studio-841rf3cg.js +5 -0
  74. package/dist/chunks/studio-8gmwgheg.js +5 -0
  75. package/dist/chunks/studio-8qm0ep50.js +5 -0
  76. package/dist/chunks/{studio-8grwxtqk.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-pre0skq6.js → studio-a3g98wjr.js} +4 -4
  79. package/dist/chunks/studio-a3shpz9y.js +5 -0
  80. package/dist/chunks/studio-amsbaaar.js +6 -0
  81. package/dist/chunks/studio-at5spjbc.js +7 -0
  82. package/dist/chunks/studio-b2xv945e.js +5 -0
  83. package/dist/chunks/studio-bn5nkafw.js +5 -0
  84. package/dist/chunks/studio-bw6q5xjf.js +9 -0
  85. package/dist/chunks/studio-c7q0t9x1.js +5 -0
  86. package/dist/chunks/studio-camnhc96.js +6 -0
  87. package/dist/chunks/studio-cffqvnzd.js +5 -0
  88. package/dist/chunks/studio-d81xfh1g.js +5 -0
  89. package/dist/chunks/studio-dgz8d0c1.js +5 -0
  90. package/dist/chunks/studio-efvfrsf8.js +5 -0
  91. package/dist/chunks/studio-er30bpcx.js +5 -0
  92. package/dist/chunks/studio-ezscgr64.js +5 -0
  93. package/dist/chunks/studio-ffrrncvz.js +5 -0
  94. package/dist/chunks/studio-fpphgn8y.js +10 -0
  95. package/dist/chunks/studio-j1kvhdjk.js +4 -0
  96. package/dist/chunks/{studio-vrmcjf9g.js → studio-j430n16g.js} +5 -5
  97. package/dist/chunks/studio-jjkg84nj.js +5 -0
  98. package/dist/chunks/studio-m0q32ars.js +4 -0
  99. package/dist/chunks/studio-m6bdst11.js +5 -0
  100. package/dist/chunks/studio-nv2cptd4.js +64 -0
  101. package/dist/chunks/studio-nwfrc98n.js +5 -0
  102. package/dist/chunks/studio-p1wgvp7r.js +5 -0
  103. package/dist/chunks/studio-pag2wncm.js +5 -0
  104. package/dist/chunks/studio-qvanvzfd.js +5 -0
  105. package/dist/chunks/studio-qwa64kt7.js +5 -0
  106. package/dist/chunks/studio-rk1zc4x3.js +928 -0
  107. package/dist/chunks/studio-se2r3ptc.js +5 -0
  108. package/dist/chunks/studio-sg2a0dh0.js +5 -0
  109. package/dist/chunks/studio-tjzjhe68.js +5 -0
  110. package/dist/chunks/{studio-wszjyh0j.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-kggey1jt.js → studio-v0jzqdjm.js} +4 -4
  112. package/dist/chunks/studio-v2w7q8r1.js +7 -0
  113. package/dist/chunks/studio-v5vjq1h0.js +4 -0
  114. package/dist/chunks/studio-v8aga3vp.js +14 -0
  115. package/dist/chunks/studio-vfcdrfmv.js +5 -0
  116. package/dist/chunks/studio-vmfkgdjf.js +5 -0
  117. package/dist/chunks/studio-wt1816jj.js +5 -0
  118. package/dist/chunks/studio-wz73q5kq.js +4 -0
  119. package/dist/chunks/studio-y04qtxvp.js +7 -0
  120. package/dist/chunks/studio-y21g8zzg.js +5 -0
  121. package/dist/chunks/{studio-zey7zsdw.js → studio-y64hrt8p.js} +7 -7
  122. package/dist/chunks/studio-ynn90f58.js +16 -0
  123. package/dist/chunks/studio-yxz682sx.js +5 -0
  124. package/dist/chunks/studio-zp7snvkq.js +5 -0
  125. package/dist/chunks/studio-zq4z6tm6.js +5 -0
  126. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  127. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  128. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  129. package/dist/chunks/toast-c9fn075p.js +4 -0
  130. package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
  131. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  132. package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
  133. package/dist/chunks/tree-mdq3v5cw.js +4 -0
  134. package/dist/chunks/{tsMode-2frah6h1.js → tsMode-sf49ee9x.js} +7 -7
  135. package/dist/chunks/workspace-jtfahpee.js +4 -0
  136. package/dist/chunks/ws-client-nze0k6mv.js +4 -0
  137. package/dist/iframe-entry.js +16 -16
  138. package/dist/manifest.json +63 -63
  139. package/dist/studio.js +97 -97
  140. package/package.json +6 -6
  141. package/src/about/about-modal.ts +4 -3
  142. package/src/account/action-flow.ts +45 -38
  143. package/src/account-status.ts +7 -2
  144. package/src/browse/library-layouts.ts +8 -5
  145. package/src/browse/library-model.ts +18 -6
  146. package/src/browse/library-pane.ts +37 -21
  147. package/src/browse/library-preview.ts +14 -9
  148. package/src/browse/library-source.ts +1 -1
  149. package/src/canvas/asset-refs.ts +24 -9
  150. package/src/canvas/asset-resolve.ts +19 -23
  151. package/src/canvas/canvas-helpers.ts +7 -6
  152. package/src/canvas/canvas-live-render.ts +44 -53
  153. package/src/canvas/canvas-patcher.ts +30 -30
  154. package/src/canvas/canvas-perf.ts +11 -5
  155. package/src/canvas/canvas-render.ts +62 -41
  156. package/src/canvas/canvas-surface.ts +5 -3
  157. package/src/canvas/canvas-utils.ts +90 -49
  158. package/src/canvas/dialog-path.ts +9 -4
  159. package/src/canvas/dialog-state.ts +1 -2
  160. package/src/canvas/diff-marks.ts +9 -16
  161. package/src/canvas/diff-toolbar.ts +8 -7
  162. package/src/canvas/edit-width-drag.ts +4 -1
  163. package/src/canvas/edit-width.ts +1 -3
  164. package/src/canvas/iframe-channel.ts +27 -13
  165. package/src/canvas/iframe-drop.ts +13 -12
  166. package/src/canvas/iframe-editable-root.ts +29 -16
  167. package/src/canvas/iframe-entry.ts +80 -63
  168. package/src/canvas/iframe-eval.ts +73 -49
  169. package/src/canvas/iframe-host.ts +135 -96
  170. package/src/canvas/iframe-inline-edit.ts +49 -30
  171. package/src/canvas/iframe-insert.ts +5 -4
  172. package/src/canvas/iframe-interaction.ts +30 -25
  173. package/src/canvas/iframe-overlay.ts +1 -1
  174. package/src/canvas/iframe-patch.ts +18 -15
  175. package/src/canvas/iframe-position.ts +12 -6
  176. package/src/canvas/iframe-protocol.ts +12 -16
  177. package/src/canvas/iframe-render.ts +36 -34
  178. package/src/canvas/iframe-slash.ts +24 -11
  179. package/src/canvas/iframe-subtree.ts +6 -2
  180. package/src/canvas/path-mapping.ts +19 -12
  181. package/src/canvas/popover-path.ts +7 -3
  182. package/src/canvas/popover-state.ts +1 -2
  183. package/src/canvas/serialize-scope.ts +13 -5
  184. package/src/canvas/stage-scrollbar.ts +2 -1
  185. package/src/canvas/surface-registry.ts +21 -3
  186. package/src/collab/collab-commands.ts +7 -2
  187. package/src/collab/collab-session.ts +84 -45
  188. package/src/collab/collab-state.ts +4 -3
  189. package/src/collab/monaco-binding.ts +16 -13
  190. package/src/collab/monaco-cursors.ts +5 -2
  191. package/src/commands/budget.ts +3 -3
  192. package/src/commands/command-args.ts +103 -71
  193. package/src/commands/context.ts +22 -20
  194. package/src/commands/keymap.ts +47 -43
  195. package/src/commands/levels.ts +3 -3
  196. package/src/commands/live-context.ts +7 -7
  197. package/src/commands/reference.ts +2 -1
  198. package/src/commands/registry.ts +12 -10
  199. package/src/commands/run-reported.ts +15 -10
  200. package/src/component-props.ts +46 -30
  201. package/src/content/collection-match.ts +5 -4
  202. package/src/content/draft-state.ts +4 -3
  203. package/src/content/entry-commands.ts +3 -2
  204. package/src/content/entry-editor.ts +29 -17
  205. package/src/content/entry-fields.ts +12 -7
  206. package/src/content/entry-model.ts +21 -12
  207. package/src/editor/canvas-context-menu.ts +1 -2
  208. package/src/editor/canvas-slash-bridge.ts +3 -6
  209. package/src/editor/content-slice.ts +16 -14
  210. package/src/editor/context-menu.ts +35 -22
  211. package/src/editor/convert-targets.ts +30 -35
  212. package/src/editor/convert-to-component.ts +11 -5
  213. package/src/editor/convert-to-repeater.ts +34 -22
  214. package/src/editor/editable-tags.ts +17 -2
  215. package/src/editor/file-drop-action.ts +21 -22
  216. package/src/editor/inline-edit-apply.ts +35 -17
  217. package/src/editor/inline-edit.ts +66 -50
  218. package/src/editor/inline-format.ts +59 -56
  219. package/src/editor/inline-link.ts +40 -15
  220. package/src/editor/insert-zone-action.ts +1 -1
  221. package/src/editor/merge-tags.ts +58 -19
  222. package/src/editor/repeater-scope.ts +39 -28
  223. package/src/editor/shortcuts.ts +32 -20
  224. package/src/editor/slash-menu.ts +1 -6
  225. package/src/files/asset-versions.ts +4 -4
  226. package/src/files/components.ts +15 -10
  227. package/src/files/elements.ts +5 -6
  228. package/src/files/file-ops.ts +77 -36
  229. package/src/files/files.ts +90 -95
  230. package/src/files/media-meta.ts +2 -1
  231. package/src/files/media-paths.ts +3 -0
  232. package/src/files/serialize-document.ts +2 -2
  233. package/src/format/constraints.ts +1 -1
  234. package/src/format/convert-file.ts +27 -13
  235. package/src/format/format-choices.ts +2 -1
  236. package/src/format/format-host.ts +76 -50
  237. package/src/github/github-auth-status.ts +27 -3
  238. package/src/github/github-auth.ts +19 -9
  239. package/src/github/github-publish.ts +24 -20
  240. package/src/grid/cell-editors.ts +46 -31
  241. package/src/grid/cell-popovers.ts +5 -3
  242. package/src/grid/edit-buffer.ts +10 -9
  243. package/src/grid/grid-controller.ts +20 -22
  244. package/src/grid/grid-layout.ts +21 -5
  245. package/src/grid/grid-open.ts +3 -6
  246. package/src/grid/grid-panel.ts +11 -4
  247. package/src/grid/grid-source.ts +8 -8
  248. package/src/grid/grid-view.ts +14 -17
  249. package/src/grid/redirects-grid.ts +14 -5
  250. package/src/grid/redirects.ts +16 -14
  251. package/src/grid/schema-columns.ts +25 -19
  252. package/src/grid/sources/connector-source.ts +47 -20
  253. package/src/grid/sources/content-source.ts +25 -24
  254. package/src/grid/sources/csv-file-source.ts +2 -2
  255. package/src/grid/tabulator-tables.d.ts +55 -34
  256. package/src/hosting/stage.ts +7 -7
  257. package/src/i18n/i18n-commands.ts +1 -2
  258. package/src/media/media-pane.ts +4 -1
  259. package/src/new-project/add-repo-modal.ts +20 -19
  260. package/src/new-project/import-tab.ts +10 -14
  261. package/src/new-project/location-fields.ts +2 -1
  262. package/src/new-project/new-project-modal.ts +12 -9
  263. package/src/packages/jxsuite-update.ts +4 -3
  264. package/src/packages/pull-package-sync.ts +26 -25
  265. package/src/page-params.ts +97 -68
  266. package/src/panels/activity-panel.ts +17 -9
  267. package/src/panels/ai-chat/attached-context.ts +13 -7
  268. package/src/panels/ai-chat/chat-view.ts +80 -73
  269. package/src/panels/ai-chat/composer.ts +30 -33
  270. package/src/panels/ai-chat/sessions-view.ts +1 -2
  271. package/src/panels/ai-panel.ts +23 -20
  272. package/src/panels/block-action-bar.ts +46 -35
  273. package/src/panels/bottom-dock.ts +5 -3
  274. package/src/panels/canvas-dnd-bridge.ts +31 -24
  275. package/src/panels/data-explorer.ts +62 -25
  276. package/src/panels/data-grid.ts +14 -11
  277. package/src/panels/dnd.ts +108 -118
  278. package/src/panels/editors.ts +52 -21
  279. package/src/panels/elements-panel.ts +10 -3
  280. package/src/panels/events-panel.ts +84 -69
  281. package/src/panels/formula-workspace.ts +76 -51
  282. package/src/panels/frontmatter-fields.ts +24 -19
  283. package/src/panels/frontmatter-panel.ts +44 -34
  284. package/src/panels/git-diff-open.ts +4 -4
  285. package/src/panels/git-panel.ts +49 -61
  286. package/src/panels/head-panel.ts +131 -111
  287. package/src/panels/i18n-panel.ts +10 -3
  288. package/src/panels/imports-panel.ts +23 -47
  289. package/src/panels/jump-bar.ts +48 -29
  290. package/src/panels/layers-panel.ts +97 -74
  291. package/src/panels/left-panel.ts +3 -3
  292. package/src/panels/pane-context.ts +31 -22
  293. package/src/panels/pane-grid.ts +49 -20
  294. package/src/panels/panel-registry.ts +22 -37
  295. package/src/panels/properties-panel.ts +175 -121
  296. package/src/panels/quick-search.ts +53 -31
  297. package/src/panels/right-panel.ts +3 -3
  298. package/src/panels/seo-modal.ts +13 -17
  299. package/src/panels/settings-menu.ts +15 -15
  300. package/src/panels/signals-panel.ts +153 -131
  301. package/src/panels/statement-editor.ts +230 -140
  302. package/src/panels/style-panel.ts +218 -205
  303. package/src/panels/style-utils.ts +114 -51
  304. package/src/panels/stylebook-doc.ts +57 -54
  305. package/src/panels/stylebook-layers-panel.ts +9 -9
  306. package/src/panels/stylebook-panel.ts +13 -17
  307. package/src/panels/tab-drop.ts +27 -11
  308. package/src/panels/tab-strip.ts +36 -26
  309. package/src/platform-errors.ts +57 -43
  310. package/src/platform.ts +58 -30
  311. package/src/platforms/cloud.ts +345 -175
  312. package/src/platforms/default-platform.ts +10 -4
  313. package/src/platforms/devserver.ts +129 -117
  314. package/src/platforms/read-batcher.ts +16 -8
  315. package/src/project-list.ts +2 -1
  316. package/src/publish/deploy-checklist.ts +8 -2
  317. package/src/publish/pages-service.ts +28 -13
  318. package/src/publish/publish-commands.ts +5 -4
  319. package/src/publish/publish-panel.ts +10 -6
  320. package/src/recent-projects.ts +15 -8
  321. package/src/resize-edges.ts +26 -36
  322. package/src/services/a11y-report.ts +26 -19
  323. package/src/services/agent-seed.ts +23 -11
  324. package/src/services/ai-ask.ts +9 -12
  325. package/src/services/ai-command-tools.ts +68 -62
  326. package/src/services/ai-import-tools.ts +80 -67
  327. package/src/services/ai-models.ts +17 -13
  328. package/src/services/ai-project-tools.ts +68 -32
  329. package/src/services/ai-session-store.ts +19 -10
  330. package/src/services/ai-system-prompt.ts +46 -20
  331. package/src/services/ai-tools.ts +71 -27
  332. package/src/services/ai-write-report.ts +20 -12
  333. package/src/services/ai-writes.ts +4 -4
  334. package/src/services/automation.ts +58 -31
  335. package/src/services/cem-export.ts +149 -58
  336. package/src/services/clock.ts +6 -1
  337. package/src/services/code-services.ts +37 -31
  338. package/src/services/context-manager.ts +14 -10
  339. package/src/services/context-resolver.ts +20 -8
  340. package/src/services/data-service.ts +19 -15
  341. package/src/services/directory-picker.ts +18 -12
  342. package/src/services/document-assistant.ts +39 -19
  343. package/src/services/gated-registry.ts +10 -6
  344. package/src/services/harness/chat-reducer.ts +23 -1
  345. package/src/services/import-client.ts +91 -38
  346. package/src/services/import-seed.ts +8 -2
  347. package/src/services/jx-validate.ts +28 -31
  348. package/src/services/live-preview.ts +0 -0
  349. package/src/services/live-surfaces.ts +6 -3
  350. package/src/services/model-uri.ts +10 -2
  351. package/src/services/module-preloads.ts +12 -8
  352. package/src/services/monaco-buffer.ts +43 -24
  353. package/src/services/monaco-lazy.ts +7 -8
  354. package/src/services/monaco-setup.ts +23 -16
  355. package/src/services/notify.ts +44 -17
  356. package/src/services/popover-report.ts +25 -10
  357. package/src/services/preview-eval.ts +20 -8
  358. package/src/services/profile.ts +13 -6
  359. package/src/services/project-path.ts +13 -10
  360. package/src/services/references.ts +0 -0
  361. package/src/services/render-critic.ts +8 -7
  362. package/src/services/settings/kernel.ts +13 -4
  363. package/src/services/settings/write-queue.ts +9 -9
  364. package/src/services/token-lint.ts +12 -10
  365. package/src/services/tool-executor.ts +17 -5
  366. package/src/services/tool-outcomes.ts +44 -24
  367. package/src/services/trusted-types.ts +24 -7
  368. package/src/settings/contexts-section.ts +11 -8
  369. package/src/settings/contributed-section.ts +79 -60
  370. package/src/settings/css-vars-editor.ts +37 -16
  371. package/src/settings/defs-editor.ts +38 -35
  372. package/src/settings/extension-rows.ts +16 -8
  373. package/src/settings/extension-sections.ts +23 -13
  374. package/src/settings/extensions-section.ts +4 -1
  375. package/src/settings/general-settings.ts +11 -8
  376. package/src/settings/locales-section.ts +20 -12
  377. package/src/settings/preferences-dialog.ts +9 -6
  378. package/src/settings/preferences-keymap.ts +7 -5
  379. package/src/settings/preferences-sections.ts +11 -5
  380. package/src/settings/project-sections.ts +1 -1
  381. package/src/settings/schema-field-ui.ts +9 -0
  382. package/src/settings/settings-document.ts +5 -5
  383. package/src/shell/tree.ts +6 -5
  384. package/src/shell.ts +104 -81
  385. package/src/site-context.ts +37 -22
  386. package/src/state.ts +41 -49
  387. package/src/store.ts +54 -34
  388. package/src/studio.ts +25 -75
  389. package/src/style/live-preview.ts +1 -1
  390. package/src/style/project-styles.ts +6 -7
  391. package/src/style/token-ref.ts +5 -4
  392. package/src/surfaces/about.ts +18 -19
  393. package/src/surfaces/add-repo.ts +17 -19
  394. package/src/surfaces/ai-chat.ts +31 -36
  395. package/src/surfaces/ai-credentials-form.ts +6 -16
  396. package/src/surfaces/ai-managed-connect.ts +3 -4
  397. package/src/surfaces/ai-model-picker.ts +3 -5
  398. package/src/surfaces/block-action-bar.ts +22 -11
  399. package/src/surfaces/boot-failure.ts +4 -5
  400. package/src/surfaces/bottom-dock.ts +9 -18
  401. package/src/surfaces/canvas-stage.ts +12 -11
  402. package/src/surfaces/cf-account-picker.ts +17 -18
  403. package/src/surfaces/commandbar.ts +14 -9
  404. package/src/surfaces/convert-repeater.ts +17 -19
  405. package/src/surfaces/data-actions.ts +9 -7
  406. package/src/surfaces/dialog.ts +26 -28
  407. package/src/surfaces/diff-toolbar.ts +9 -7
  408. package/src/surfaces/doc-header.ts +10 -19
  409. package/src/surfaces/empty-state.ts +7 -10
  410. package/src/surfaces/entry-editor.ts +14 -11
  411. package/src/surfaces/expression-editor.ts +11 -25
  412. package/src/surfaces/files-panel.ts +27 -14
  413. package/src/surfaces/formula-palette.ts +4 -5
  414. package/src/surfaces/git-panel.ts +7 -15
  415. package/src/surfaces/github-auth.ts +16 -20
  416. package/src/surfaces/github-publish.ts +17 -22
  417. package/src/surfaces/grid-cell.ts +30 -31
  418. package/src/surfaces/grid-open.ts +10 -14
  419. package/src/surfaces/grid-panel.ts +13 -9
  420. package/src/surfaces/grid-replace.ts +13 -13
  421. package/src/surfaces/grid-views.ts +15 -18
  422. package/src/surfaces/inspector-dock.ts +13 -12
  423. package/src/surfaces/jump-bar.ts +5 -6
  424. package/src/surfaces/jxsuite-update.ts +16 -22
  425. package/src/surfaces/library-pane.ts +19 -20
  426. package/src/surfaces/logic-panel.ts +17 -30
  427. package/src/surfaces/logic-workspace.ts +13 -15
  428. package/src/surfaces/media-browser.ts +11 -10
  429. package/src/surfaces/media-field.ts +4 -5
  430. package/src/surfaces/media-pane.ts +8 -7
  431. package/src/surfaces/menu.ts +29 -23
  432. package/src/surfaces/navigator-dock.ts +11 -12
  433. package/src/surfaces/new-project.ts +27 -26
  434. package/src/surfaces/pane-context.ts +20 -25
  435. package/src/surfaces/pane-grid.ts +15 -10
  436. package/src/surfaces/panel-activity.ts +5 -6
  437. package/src/surfaces/panel-data.ts +3 -4
  438. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  439. package/src/surfaces/panel-elements.ts +5 -7
  440. package/src/surfaces/panel-i18n.ts +5 -7
  441. package/src/surfaces/panel-imports.ts +6 -13
  442. package/src/surfaces/panel-outline.ts +25 -19
  443. package/src/surfaces/panel-page.ts +11 -18
  444. package/src/surfaces/panel-problems.ts +5 -7
  445. package/src/surfaces/panel-signals.ts +20 -34
  446. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  447. package/src/surfaces/preferences.ts +21 -11
  448. package/src/surfaces/progress-modal.ts +15 -9
  449. package/src/surfaces/properties-panel.json +1 -1
  450. package/src/surfaces/properties-panel.ts +20 -42
  451. package/src/surfaces/publish.ts +18 -18
  452. package/src/surfaces/push-plan.ts +7 -8
  453. package/src/surfaces/rail.ts +13 -13
  454. package/src/surfaces/reference-field.ts +11 -15
  455. package/src/surfaces/schema-builder.ts +16 -22
  456. package/src/surfaces/schema-form.ts +15 -25
  457. package/src/surfaces/secret-field.ts +9 -6
  458. package/src/surfaces/seo.ts +21 -15
  459. package/src/surfaces/settings-contexts.ts +9 -7
  460. package/src/surfaces/settings-contributed.ts +14 -10
  461. package/src/surfaces/settings-css-vars.ts +5 -12
  462. package/src/surfaces/settings-defs.json +2 -2
  463. package/src/surfaces/settings-defs.ts +17 -21
  464. package/src/surfaces/settings-deploy.ts +8 -15
  465. package/src/surfaces/settings-extensions.ts +5 -6
  466. package/src/surfaces/settings-head.ts +33 -39
  467. package/src/surfaces/settings-locales.ts +8 -20
  468. package/src/surfaces/settings-overview.ts +5 -6
  469. package/src/surfaces/settings-packages.ts +8 -7
  470. package/src/surfaces/settings-pane.ts +9 -18
  471. package/src/surfaces/settings-rawjson.ts +5 -6
  472. package/src/surfaces/shell.ts +1 -2
  473. package/src/surfaces/slash-menu.ts +19 -9
  474. package/src/surfaces/statements.ts +13 -18
  475. package/src/surfaces/statusbar.ts +17 -14
  476. package/src/surfaces/style-panel.ts +18 -31
  477. package/src/surfaces/stylebook-chrome.ts +3 -5
  478. package/src/surfaces/tab-strip.ts +14 -13
  479. package/src/surfaces/target-line.ts +6 -7
  480. package/src/surfaces/welcome.ts +5 -7
  481. package/src/tabs/patch-ops.ts +4 -3
  482. package/src/tabs/project-config.ts +32 -21
  483. package/src/tabs/selection.ts +36 -8
  484. package/src/tabs/tab.ts +52 -41
  485. package/src/tabs/transact.ts +98 -53
  486. package/src/types.ts +32 -17
  487. package/src/ui/ai-credentials-form.ts +10 -13
  488. package/src/ui/ai-model-picker.ts +3 -3
  489. package/src/ui/cf-account-picker.ts +7 -9
  490. package/src/ui/color-selector.ts +9 -5
  491. package/src/ui/dynamic-slot.ts +7 -8
  492. package/src/ui/expression-editor.ts +112 -105
  493. package/src/ui/form-controls.ts +57 -48
  494. package/src/ui/formula-catalog.ts +239 -230
  495. package/src/ui/formula-chips.ts +33 -18
  496. package/src/ui/layers.ts +44 -31
  497. package/src/ui/media-picker.ts +18 -9
  498. package/src/ui/popover-surface.ts +20 -12
  499. package/src/ui/progress-modal.ts +13 -8
  500. package/src/ui/regions.ts +7 -6
  501. package/src/ui/schema-form.ts +113 -70
  502. package/src/ui/surface.ts +71 -8
  503. package/src/ui/timing.ts +9 -0
  504. package/src/ui/value-source.ts +44 -31
  505. package/src/ui/virtual-window.ts +3 -2
  506. package/src/utils/base64.ts +3 -1
  507. package/src/utils/edit-display.ts +73 -73
  508. package/src/utils/element-selectors.ts +3 -2
  509. package/src/utils/google-fonts.ts +15 -14
  510. package/src/utils/inherited-style.ts +18 -20
  511. package/src/utils/link-target.ts +1 -1
  512. package/src/utils/preview-format.ts +25 -3
  513. package/src/utils/strip-events.ts +49 -22
  514. package/src/utils/studio-utils.ts +29 -14
  515. package/src/view.ts +2 -3
  516. package/src/workspace/pane-derive.ts +10 -12
  517. package/src/workspace/session.ts +53 -43
  518. package/src/workspace/workspace.ts +40 -36
  519. package/dist/chunks/adapter-f93pafd7.js +0 -4
  520. package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
  521. package/dist/chunks/cf-settings-125tdm0w.js +0 -4
  522. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  523. package/dist/chunks/color-field-embq5ctg.js +0 -4
  524. package/dist/chunks/color-fpezvnkt.js +0 -4
  525. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  526. package/dist/chunks/combobox-773hdzyj.js +0 -4
  527. package/dist/chunks/components-ax2f1fnn.js +0 -4
  528. package/dist/chunks/content-source-108aqtk1.js +0 -4
  529. package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
  530. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  531. package/dist/chunks/editor-pfgdmkb0.js +0 -4
  532. package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
  533. package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
  534. package/dist/chunks/file-ops-meej5mqf.js +0 -4
  535. package/dist/chunks/files-44vp8a2s.js +0 -4
  536. package/dist/chunks/format-host-7q1petb9.js +0 -4
  537. package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
  538. package/dist/chunks/git-panel-zngbymvd.js +0 -4
  539. package/dist/chunks/grid-view-sx9vynsp.js +0 -51
  540. package/dist/chunks/icons-p44xhjf0.js +0 -4
  541. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  542. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  543. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  544. package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
  545. package/dist/chunks/index-wkyfjeqz.js +0 -4
  546. package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
  547. package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
  548. package/dist/chunks/layers-xd92fg8d.js +0 -4
  549. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  550. package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
  551. package/dist/chunks/media-picker-0svzkdyb.js +0 -4
  552. package/dist/chunks/menu-37d07z9m.js +0 -4
  553. package/dist/chunks/menu-5c55ea3d.js +0 -4
  554. package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
  555. package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
  556. package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
  557. package/dist/chunks/notify-0xgtn8q1.js +0 -4
  558. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  559. package/dist/chunks/parse-897fvqah.js +0 -4
  560. package/dist/chunks/platform-v1qctbe6.js +0 -4
  561. package/dist/chunks/popover-8htra4er.js +0 -4
  562. package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
  563. package/dist/chunks/quick-search-a54e6t5n.js +0 -4
  564. package/dist/chunks/references-gmqp82fs.js +0 -4
  565. package/dist/chunks/right-panel-v7t9awbk.js +0 -4
  566. package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
  567. package/dist/chunks/select-n3v7gwas.js +0 -4
  568. package/dist/chunks/split-pff8f3ze.js +0 -4
  569. package/dist/chunks/studio-0bhx5hz6.js +0 -5
  570. package/dist/chunks/studio-0k1ddnyy.js +0 -6
  571. package/dist/chunks/studio-1b04pd0j.js +0 -64
  572. package/dist/chunks/studio-4dwbj6gb.js +0 -5
  573. package/dist/chunks/studio-4tanh828.js +0 -5
  574. package/dist/chunks/studio-55h4mstj.js +0 -4
  575. package/dist/chunks/studio-5tnvjkz4.js +0 -5
  576. package/dist/chunks/studio-60dqgb0c.js +0 -5
  577. package/dist/chunks/studio-61dp09qg.js +0 -9
  578. package/dist/chunks/studio-63epcrj2.js +0 -5
  579. package/dist/chunks/studio-74k29dy9.js +0 -5
  580. package/dist/chunks/studio-7vg6jcd3.js +0 -5
  581. package/dist/chunks/studio-7zx31knw.js +0 -9
  582. package/dist/chunks/studio-8bxk97km.js +0 -5
  583. package/dist/chunks/studio-933e30n4.js +0 -5
  584. package/dist/chunks/studio-98wnwhbg.js +0 -5
  585. package/dist/chunks/studio-9mccjwjh.js +0 -14
  586. package/dist/chunks/studio-a2ke1e4t.js +0 -5
  587. package/dist/chunks/studio-e3a2a6v3.js +0 -4
  588. package/dist/chunks/studio-e81q1vb9.js +0 -5
  589. package/dist/chunks/studio-epgrmqqm.js +0 -5
  590. package/dist/chunks/studio-ery42sqr.js +0 -4
  591. package/dist/chunks/studio-g1shz58g.js +0 -5
  592. package/dist/chunks/studio-gf0fz03c.js +0 -5
  593. package/dist/chunks/studio-gjtpe62q.js +0 -6
  594. package/dist/chunks/studio-gkskhg7m.js +0 -5
  595. package/dist/chunks/studio-gx4dnjzd.js +0 -5
  596. package/dist/chunks/studio-j03zga3y.js +0 -9
  597. package/dist/chunks/studio-jhpxeckz.js +0 -5
  598. package/dist/chunks/studio-k01r7ykp.js +0 -5
  599. package/dist/chunks/studio-kk7h30ne.js +0 -7
  600. package/dist/chunks/studio-kt1zqney.js +0 -5
  601. package/dist/chunks/studio-m3cwhvye.js +0 -5
  602. package/dist/chunks/studio-mcayt6hz.js +0 -5
  603. package/dist/chunks/studio-myjcghv3.js +0 -5
  604. package/dist/chunks/studio-n8bxwc3y.js +0 -4
  605. package/dist/chunks/studio-ngm8gvpb.js +0 -5
  606. package/dist/chunks/studio-nj5a01jy.js +0 -928
  607. package/dist/chunks/studio-pcgz8heb.js +0 -5
  608. package/dist/chunks/studio-qcsq0t15.js +0 -5
  609. package/dist/chunks/studio-qkstvve9.js +0 -5
  610. package/dist/chunks/studio-qv1pwd3c.js +0 -5
  611. package/dist/chunks/studio-rc6dvxjb.js +0 -7
  612. package/dist/chunks/studio-s8dmmz66.js +0 -5
  613. package/dist/chunks/studio-sp5xzbj4.js +0 -6
  614. package/dist/chunks/studio-szsjbj0g.js +0 -5
  615. package/dist/chunks/studio-t1xzawhr.js +0 -16
  616. package/dist/chunks/studio-t6b6qe31.js +0 -5
  617. package/dist/chunks/studio-tdcprbqb.js +0 -5
  618. package/dist/chunks/studio-vyc0b4he.js +0 -10
  619. package/dist/chunks/studio-w0cgf6jg.js +0 -5
  620. package/dist/chunks/studio-w3hskzqk.js +0 -5
  621. package/dist/chunks/studio-xgrgcdyh.js +0 -9
  622. package/dist/chunks/studio-xz2yxfcb.js +0 -5
  623. package/dist/chunks/studio-y6n42tgs.js +0 -5
  624. package/dist/chunks/studio-yb560vxr.js +0 -5
  625. package/dist/chunks/studio-yn9f8vtx.js +0 -5
  626. package/dist/chunks/studio-yw05w8f0.js +0 -7
  627. package/dist/chunks/studio-z16sgavc.js +0 -5
  628. package/dist/chunks/studio-zyqn40w4.js +0 -5
  629. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  630. package/dist/chunks/tabs-jwthg40w.js +0 -4
  631. package/dist/chunks/textfield-spy3hc77.js +0 -4
  632. package/dist/chunks/toast-4d35zd64.js +0 -4
  633. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  634. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  635. package/dist/chunks/tree-h19v1jfz.js +0 -4
  636. package/dist/chunks/workspace-zt81g1ms.js +0 -4
  637. package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
@@ -10,7 +10,7 @@
10
10
 
11
11
  import { createToolDefinition } from "@jxsuite/ai/tools";
12
12
  import type { ToolRegistry, ToolResult, WriteLedger } from "@jxsuite/ai/tools";
13
- import type { JxMutableNode, JxPath, JxStateDefinition } from "@jxsuite/schema/types";
13
+ import type { JsonObject, JxMutableNode, JxPath } from "@jxsuite/schema/types";
14
14
  import { getNodeAtPath } from "../state";
15
15
  import type { Tab } from "../tabs/tab";
16
16
  import {
@@ -32,7 +32,7 @@ import {
32
32
  snapshotBeforeWrite,
33
33
  translateValidationError,
34
34
  } from "./ai-write-report";
35
- import type { RenderVerdict } from "./ai-write-report";
35
+ import type { CandidateDocument, RenderVerdict } from "./ai-write-report";
36
36
 
37
37
  /* Re-exported from its new home so `ai-project-tools.ts` and the tests keep their import: the
38
38
  translation moved with the verdict it belongs to (`ai-write-report.ts`), where every document
@@ -43,6 +43,14 @@ const PATH_DESCRIPTION =
43
43
  "Path to a node in the document, as a JSON array of keys/indices from the root " +
44
44
  '(e.g. ["children", 0, "children", 1]). Use read_document to discover valid paths.';
45
45
 
46
+ /**
47
+ * The node at `path`, typed as what {@link getNodeAtPath} actually answers: a path the model made up
48
+ * runs off the tree, and that is `undefined`, which every tool here reports as "No node exists".
49
+ */
50
+ function nodeAt(doc: JxMutableNode, path: JxPath): JxMutableNode | undefined {
51
+ return getNodeAtPath(doc, path);
52
+ }
53
+
46
54
  /** Steering error for document tools called with no active tab. */
47
55
  function noDocError(): ToolResult {
48
56
  return {
@@ -64,8 +72,8 @@ function noDocError(): ToolResult {
64
72
  * @param {import("../tabs/tab").Tab} tab
65
73
  * @param {(t: import("../tabs/tab").Tab) => void} mutationFn
66
74
  * @param {string} summary
67
- * @param {(doc: unknown) => Promise<string[]>} validate
68
- * @param {((doc: unknown) => Promise<RenderVerdict>) | undefined} renderCheck
75
+ * @param {(doc: CandidateDocument) => Promise<string[]>} validate
76
+ * @param {((doc: CandidateDocument) => Promise<RenderVerdict>) | undefined} renderCheck
69
77
  * @param {Record<string, string> | undefined} projectStyle
70
78
  * @returns {Promise<import("@jxsuite/ai/tools").ToolResult>}
71
79
  */
@@ -74,8 +82,8 @@ async function applyAndValidate(
74
82
  tab: Tab,
75
83
  mutationFn: (t: Tab) => void,
76
84
  summary: string,
77
- validate: (doc: unknown) => Promise<string[]>,
78
- renderCheck: ((doc: unknown) => Promise<RenderVerdict>) | undefined,
85
+ validate: (doc: CandidateDocument) => Promise<string[]>,
86
+ renderCheck: ((doc: CandidateDocument) => Promise<RenderVerdict>) | undefined,
79
87
  projectStyle: Record<string, string> | undefined,
80
88
  ): Promise<ToolResult> {
81
89
  const deps = { getProjectStyle: () => projectStyle, renderCheck, validate };
@@ -109,9 +117,9 @@ async function applyAndValidate(
109
117
  * @param {import("@jxsuite/ai/tools").ToolRegistry} registry
110
118
  * @param {{
111
119
  * getTab: () => import("../tabs/tab").Tab | null;
112
- * validate?: (doc: unknown) => Promise<string[]>;
120
+ * validate?: (doc: CandidateDocument) => Promise<string[]>;
113
121
  * saveFile?: (relPath: string, content: string) => Promise<void>;
114
- * renderCheck?: (doc: unknown) => Promise<{ ok: true } | { ok: false; error: string }>;
122
+ * renderCheck?: (doc: CandidateDocument) => Promise<{ ok: true } | { ok: false; error: string }>;
115
123
  * projectStyle?: Record<string, string>;
116
124
  * getProjectStyle?: () => Record<string, string> | undefined;
117
125
  * findOpenTab?: (path: string) => import("../tabs/tab").Tab | null;
@@ -131,9 +139,9 @@ export function registerAiTools(
131
139
  reloadTab,
132
140
  }: {
133
141
  getTab: () => Tab | null;
134
- validate?: (doc: unknown) => Promise<string[]>;
142
+ validate?: (doc: CandidateDocument) => Promise<string[]>;
135
143
  saveFile?: (relPath: string, content: string) => Promise<void>;
136
- renderCheck?: (doc: unknown) => Promise<{ ok: true } | { ok: false; error: string }>;
144
+ renderCheck?: (doc: CandidateDocument) => Promise<{ ok: true } | { ok: false; error: string }>;
137
145
  projectStyle?: Record<string, string> | undefined;
138
146
  /**
139
147
  * Live variant of `projectStyle` — takes precedence; re-read per tool call so a project
@@ -195,9 +203,11 @@ export function registerAiTools(
195
203
  if (!tab) {
196
204
  return noDocError();
197
205
  }
206
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed, which refuses
207
+ a `path` that is present but not an array. Its items are not checked; a key that does
208
+ not resolve makes `nodeAt` answer undefined, reported just below. */
198
209
  const { path } = args as { path?: JxPath };
199
- const node =
200
- path && path.length > 0 ? getNodeAtPath(tab.doc.document, path) : tab.doc.document;
210
+ const node = path && path.length > 0 ? nodeAt(tab.doc.document, path) : tab.doc.document;
201
211
  if (node === undefined) {
202
212
  return { success: false, error: `No node exists at path ${JSON.stringify(path)}.` };
203
213
  }
@@ -239,8 +249,12 @@ export function registerAiTools(
239
249
  if (!tab) {
240
250
  return noDocError();
241
251
  }
252
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed: `path` is a
253
+ present array and `key` a present string. `value` declares no type, so it is any JSON
254
+ value or absent, all of which `JxNodeValue` includes. A `path` whose items do not resolve
255
+ is caught by `nodeAt` just below. */
242
256
  const { path, key, value } = args as { path: JxPath; key: string; value?: JxNodeValue };
243
- const node = getNodeAtPath(tab.doc.document, path);
257
+ const node = nodeAt(tab.doc.document, path);
244
258
  if (node === undefined) {
245
259
  return { success: false, error: `No node exists at path ${JSON.stringify(path)}.` };
246
260
  }
@@ -286,6 +300,11 @@ export function registerAiTools(
286
300
  if (!tab) {
287
301
  return noDocError();
288
302
  }
303
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed: `parentPath` is
304
+ a present array, `node` a present object, and `index` a present number — or a numeric
305
+ string, which the validator also admits for an integer and `splice` coerces alike.
306
+ `node` is a model-written tree whose shape the schema check after the write judges, and
307
+ a `parentPath` that does not resolve is caught just below. */
289
308
  const {
290
309
  parentPath,
291
310
  index,
@@ -295,7 +314,7 @@ export function registerAiTools(
295
314
  index: number;
296
315
  node: JxMutableNode;
297
316
  };
298
- const parent = getNodeAtPath(tab.doc.document, parentPath);
317
+ const parent = nodeAt(tab.doc.document, parentPath);
299
318
  if (parent === undefined) {
300
319
  return { success: false, error: `No node exists at path ${JSON.stringify(parentPath)}.` };
301
320
  }
@@ -373,12 +392,12 @@ export function registerAiTools(
373
392
  if (!tab) {
374
393
  return noDocError();
375
394
  }
376
- const { path, property, value } = args as {
377
- path: JxPath;
378
- property: string;
379
- value?: unknown;
380
- };
381
- if (getNodeAtPath(tab.doc.document, path) === undefined) {
395
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed: `path` is a
396
+ present array and `property` a present string; a `path` that does not resolve is caught
397
+ just below. `value` is read untyped and stringified. */
398
+ const { path, property } = args as { path: JxPath; property: string };
399
+ const { value } = args;
400
+ if (nodeAt(tab.doc.document, path) === undefined) {
382
401
  return { success: false, error: `No node exists at path ${JSON.stringify(path)}.` };
383
402
  }
384
403
  const prop = property;
@@ -420,8 +439,11 @@ export function registerAiTools(
420
439
  if (!tab) {
421
440
  return noDocError();
422
441
  }
442
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed: `path` is a
443
+ present array and `value` a present string; a `path` that does not resolve is caught
444
+ just below. */
423
445
  const { path, value } = args as { path: JxPath; value: string };
424
- if (getNodeAtPath(tab.doc.document, path) === undefined) {
446
+ if (nodeAt(tab.doc.document, path) === undefined) {
425
447
  return { success: false, error: `No node exists at path ${JSON.stringify(path)}.` };
426
448
  }
427
449
  return applyAndValidate(
@@ -469,7 +491,10 @@ export function registerAiTools(
469
491
  if (!tab) {
470
492
  return noDocError();
471
493
  }
472
- const { key, value } = args as { key: string; value: JxStateDefinition };
494
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed, so `key` is a
495
+ present string. */
496
+ const { key } = args as { key: string };
497
+ const { value } = args;
473
498
  if (tab.doc.document.state && tab.doc.document.state[key] !== undefined) {
474
499
  return {
475
500
  success: false,
@@ -482,6 +507,10 @@ export function registerAiTools(
482
507
  /* `mutateAddDef` rather than `mutateUpdateProperty`: the latter deletes on "", which is
483
508
  wrong for a state default (`"title": ""`). It also records the op, so the canvas, the
484
509
  history and collaborators each get the edit as an edit. */
510
+ /* SAFETY: `value` is required, so the registry refused it missing or null; it is the
511
+ model's state entry, possibly a scalar default (`0`, `""`) the schema admits.
512
+ `mutateAddDef` only clones `def` and stores it under `state[key]`, never reading it
513
+ as the object its parameter names. */
485
514
  (t) => mutateAddDef(t, key, value as Record<string, JsonValue>),
486
515
  `Added state "${key}".`,
487
516
  validate,
@@ -519,7 +548,10 @@ export function registerAiTools(
519
548
  if (!tab) {
520
549
  return noDocError();
521
550
  }
522
- const { key, value } = args as { key: string; value?: JxStateDefinition | null };
551
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed, so `key` is a
552
+ present string. */
553
+ const { key } = args as { key: string };
554
+ const { value } = args;
523
555
  if (!tab.doc.document.state || tab.doc.document.state[key] === undefined) {
524
556
  return {
525
557
  success: false,
@@ -535,6 +567,9 @@ export function registerAiTools(
535
567
  if (value == null) {
536
568
  mutateRemoveDef(t, key);
537
569
  } else {
570
+ /* SAFETY: the model's state entry, possibly a scalar default the schema admits.
571
+ `mutateAddDef` only clones `def` and stores it under `state[key]`, never reading
572
+ it as the object its parameter names. */
538
573
  mutateAddDef(t, key, value as Record<string, JsonValue>);
539
574
  }
540
575
  },
@@ -580,6 +615,9 @@ export function registerAiTools(
580
615
  if (!tab) {
581
616
  return noDocError();
582
617
  }
618
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed: both paths are
619
+ present arrays, and `toIndex` a present number or numeric string (the validator admits
620
+ both for an integer). Paths that do not resolve are caught just below. */
583
621
  const { fromPath, toParentPath, toIndex } = args as {
584
622
  fromPath: JxPath;
585
623
  toParentPath: JxPath;
@@ -588,13 +626,13 @@ export function registerAiTools(
588
626
  if (fromPath.length < 2) {
589
627
  return { success: false, error: "Cannot move the document root." };
590
628
  }
591
- if (getNodeAtPath(tab.doc.document, fromPath) === undefined) {
629
+ if (nodeAt(tab.doc.document, fromPath) === undefined) {
592
630
  return {
593
631
  success: false,
594
632
  error: `No node exists at fromPath ${JSON.stringify(fromPath)}.`,
595
633
  };
596
634
  }
597
- if (getNodeAtPath(tab.doc.document, toParentPath) === undefined) {
635
+ if (nodeAt(tab.doc.document, toParentPath) === undefined) {
598
636
  return {
599
637
  success: false,
600
638
  error: `No node exists at toParentPath ${JSON.stringify(toParentPath)}.`,
@@ -644,7 +682,10 @@ export function registerAiTools(
644
682
  error: "File operations are not available in this environment.",
645
683
  };
646
684
  }
647
- const { path, content } = args as { path: string; content: object };
685
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed: `path` is a
686
+ present string and `content` a present JSON object (not an array, not null). Whether that
687
+ object is a Jx document is what `validate` and `renderCheck` below decide. */
688
+ const { path, content } = args as { path: string; content: JsonObject };
648
689
  // Inside the project or not at all (ai.md §4): the platform write is given this path.
649
690
  const relPath = normalizeRelPath(path);
650
691
  if (relPath === null) {
@@ -728,7 +769,10 @@ export function registerAiTools(
728
769
  error: "File operations are not available in this environment.",
729
770
  };
730
771
  }
731
- const { path, content } = args as { path: string; content: object };
772
+ /* SAFETY: a strict tool runs only after the registry's `validate()` passed: `path` is a
773
+ present string and `content` a present JSON object (not an array, not null). Whether that
774
+ object is a Jx document is what `validate` and `renderCheck` below decide. */
775
+ const { path, content } = args as { path: string; content: JsonObject };
732
776
  const relPath = normalizeRelPath(path);
733
777
  if (relPath === null) {
734
778
  return invalidPathResult(path);
@@ -2,26 +2,27 @@
2
2
  * Ai-write-report.ts — what the model is told after a document write, whoever made it.
3
3
  *
4
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
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
7
  * `services/ai-command-tools.ts` — so it lives here, in two functions the caller brackets its write
8
8
  * with:
9
9
  *
10
- * 1. {@link snapshotBeforeWrite} reads the document's schema errors and render state BEFORE the
11
- * write, because the loop's signal (specs/ai.md §3.1) is "what did this edit newly introduce",
12
- * not "is the document valid": a page that was already broken must not make every subsequent
13
- * edit read as the culprit.
10
+ * 1. {@link snapshotBeforeWrite} reads the document's schema errors and render state BEFORE the write,
11
+ * because the loop's signal (specs/ai.md §3.1) is "what did this edit newly introduce", not "is
12
+ * the document valid": a page that was already broken must not make every subsequent edit read
13
+ * as the culprit.
14
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.
15
+ * fix hint the model can act on, running the render check only when rendering worked before, and
16
+ * appending the soft token-discipline hints to a success.
17
17
  *
18
- * The change stays applied either way (optimistic apply + undo, specs/ai.md §3.1); reporting the errors lets
19
- * the agent loop self-correct on the next round.
18
+ * The change stays applied either way (optimistic apply + undo, specs/ai.md §3.1); reporting the
19
+ * errors lets the agent loop self-correct on the next round.
20
20
  *
21
21
  * @license MIT
22
22
  */
23
23
 
24
24
  import type { ToolResult } from "@jxsuite/ai/tools";
25
+ import type { JsonValue, JxMutableNode } from "@jxsuite/schema/types";
25
26
  import { toRaw } from "../reactivity";
26
27
  import type { Tab } from "../tabs/tab";
27
28
  import { flagHardcodedTokens, formatTokenHints } from "./token-lint";
@@ -29,12 +30,19 @@ import { flagHardcodedTokens, formatTokenHints } from "./token-lint";
29
30
  /** A render probe's answer: rendered, or the message it threw. */
30
31
  export type RenderVerdict = { ok: true } | { ok: false; error: string };
31
32
 
33
+ /**
34
+ * A document as the validator and the render probe receive it: the live tree of an open tab, or the
35
+ * JSON a tool was handed (a `create_page` argument, a parsed `write_file` body) before anything has
36
+ * said it is a document. Judging that is what the two of them are for.
37
+ */
38
+ export type CandidateDocument = JxMutableNode | JsonValue;
39
+
32
40
  /** What a write reporter needs. Every member is what `registerAiTools` already takes by injection. */
33
41
  export interface WriteReportDeps {
34
42
  /** Schema errors for a document, as raw ajv sentences. */
35
- validate: (doc: unknown) => Promise<string[]>;
43
+ validate: (doc: CandidateDocument) => Promise<string[]>;
36
44
  /** The detached-DOM render probe, when the host has one. */
37
- renderCheck?: ((doc: unknown) => Promise<RenderVerdict>) | undefined;
45
+ renderCheck?: ((doc: CandidateDocument) => Promise<RenderVerdict>) | undefined;
38
46
  /** The project's design tokens, read per call so a project opened mid-session contributes. */
39
47
  getProjectStyle?: (() => Record<string, string> | undefined) | undefined;
40
48
  }
@@ -22,7 +22,7 @@
22
22
  * @docs studio/ai/chat
23
23
  */
24
24
 
25
- import type { Message } from "@jxsuite/ai/chat-state";
25
+ import type { LiveMessage } from "@jxsuite/ai/messages";
26
26
  import { createLedger } from "@jxsuite/ai/tools";
27
27
  import type { AiWrite, WriteLedger } from "@jxsuite/ai/tools";
28
28
 
@@ -113,7 +113,7 @@ export function summarizeWrites(writes: AiWrite[]): string {
113
113
  return failed > 0 ? `${failed} change${failed === 1 ? "" : "s"} failed` : "";
114
114
  }
115
115
  const files = `Changed ${paths.size} file${paths.size === 1 ? "" : "s"}`;
116
- const diskPaths = new Set(applied.filter((w) => w.disk).map((w) => w.path));
116
+ const diskPaths = new Set(applied.flatMap((w) => (w.disk ? [w.path] : [])));
117
117
  const parts = [files];
118
118
  if (diskPaths.size > 0) {
119
119
  parts.push(
@@ -150,13 +150,13 @@ export function resetAiWrites(): void {
150
150
  * message in it belongs to some other conversation: filing there would draw "Changed 1 file", and
151
151
  * Restore, under a reply that changed nothing.
152
152
  *
153
- * @param {readonly Message[]} messages
153
+ * @param {readonly LiveMessage[]} messages
154
154
  * @param {string} [userId] - The id of the user message this turn answers; without one, the whole
155
155
  * transcript is the turn
156
156
  * @returns {string | null} Null when the turn drew nothing (so it ran no tool either), or when its
157
157
  * user message has left the transcript
158
158
  */
159
- export function turnAnchor(messages: readonly Message[], userId?: string): string | null {
159
+ export function turnAnchor(messages: readonly LiveMessage[], userId?: string): string | null {
160
160
  let anchor: string | null = null;
161
161
  for (let index = messages.length - 1; index >= 0; index--) {
162
162
  const message = messages[index]!;
@@ -37,10 +37,12 @@ import { seedProjectList } from "../project-list";
37
37
  import { activeTab } from "../workspace/workspace";
38
38
  import { shell } from "../shell";
39
39
  import { collabState } from "../collab/collab-state";
40
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
40
41
  import { canvasPointAt, revealCanvasPath } from "../canvas/iframe-host";
41
42
  import { probeIdle } from "./idle";
42
43
  import type { CanvasPoint } from "../canvas/iframe-host";
43
44
  import type { IdleOptions } from "./idle";
45
+ import type { CommandArgValues } from "../commands/command-args";
44
46
  import type { CommandContext } from "../commands/context";
45
47
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
46
48
  import type { PeerPresence } from "../collab/collab-state";
@@ -50,9 +52,6 @@ import type { GitBranchesResult, GitStatusResult, ProjectListEntry } from "../ty
50
52
  import type { GitLogEntry } from "../shell";
51
53
  import type { JxPath } from "../state";
52
54
 
53
- /** Loosely-typed arguments, as they arrive from a manifest step, a palette prompt or a tool call. */
54
- export type AutomationArgs = Record<string, unknown>;
55
-
56
55
  /**
57
56
  * What the hook needs that it cannot import.
58
57
  *
@@ -130,7 +129,7 @@ export interface ManifestId {
130
129
  * the same debt. Five `refused` entries are NOT a countdown: they are §13.5's normative refusals,
131
130
  * and they stay so that a caller reaching for one gets the reason instead of "unknown command".
132
131
  */
133
- export const AUTOMATION_COMMANDS: Readonly<Record<string, ManifestId>> = {
132
+ export const AUTOMATION_COMMANDS = {
134
133
  "file.contextMenu": {
135
134
  disposition: "refused",
136
135
  note: "opening a menu to press an item names a control; the ITEM is the command",
@@ -152,7 +151,13 @@ export const AUTOMATION_COMMANDS: Readonly<Record<string, ManifestId>> = {
152
151
  disposition: "refused",
153
152
  note: "the status bar is not staged — if a capture needs a calm shell, the app must BE calm",
154
153
  },
155
- };
154
+ } as const satisfies Readonly<Record<string, ManifestId>>;
155
+
156
+ /**
157
+ * {@link AUTOMATION_COMMANDS} keyed for lookup by an arbitrary id. A Map rather than an index into
158
+ * the object, so an id such as `"constructor"` finds nothing instead of `Object.prototype`'s.
159
+ */
160
+ const COMMAND_GAPS: ReadonlyMap<string, ManifestId> = new Map(Object.entries(AUTOMATION_COMMANDS));
156
161
 
157
162
  // ─── The seed registry, under the Remote Rule ─────────────────────────────────
158
163
 
@@ -161,7 +166,7 @@ export interface SeedDefinition {
161
166
  id: string;
162
167
  /** The network or IPC boundary this seed stands in for. The Remote Rule, written down per seed. */
163
168
  boundary: string;
164
- run: (args: AutomationArgs) => void | Promise<void>;
169
+ run: (args: CommandArgValues) => void | Promise<void>;
165
170
  }
166
171
 
167
172
  /**
@@ -170,7 +175,7 @@ export interface SeedDefinition {
170
175
  * Every one of these was a method on the old surface. Each writes state a USER writes, so each is a
171
176
  * COMMAND — and a fixture that stages it photographs a state no session could have reached.
172
177
  */
173
- export const REFUSED_SEEDS: Readonly<Record<string, string>> = {
178
+ export const REFUSED_SEEDS = {
174
179
  openSettings: 'a user opens Settings — run("settings.open")',
175
180
  select: 'a user selects a node — run("selection.set", { path })',
176
181
  setActivity: 'a user picks a Navigator panel — run("navigator.showPanel", { panel })',
@@ -178,9 +183,12 @@ export const REFUSED_SEEDS: Readonly<Record<string, string>> = {
178
183
  setStatus:
179
184
  "the status bar reports what the app just did; staging it is the one lie the Remote Rule (studio.md §13.5) names outright",
180
185
  setZoom: 'a user zooms — run("canvas.setZoom", { zoom })',
181
- };
186
+ } as const satisfies Readonly<Record<string, string>>;
182
187
 
183
- function arrayArg<T>(args: AutomationArgs, key: string): T[] {
188
+ /** {@link REFUSED_SEEDS} keyed for lookup by an arbitrary seed name, as {@link COMMAND_GAPS} is. */
189
+ const SEED_REFUSALS: ReadonlyMap<string, string> = new Map(Object.entries(REFUSED_SEEDS));
190
+
191
+ function arrayArg<T>(args: CommandArgValues, key: string): T[] {
184
192
  const value = args[key];
185
193
  if (value === undefined) {
186
194
  return [];
@@ -188,23 +196,28 @@ function arrayArg<T>(args: AutomationArgs, key: string): T[] {
188
196
  if (!Array.isArray(value)) {
189
197
  throw new TypeError(`seed argument "${key}" must be an array`);
190
198
  }
199
+ /* SAFETY: a seed's arguments are a fixture written against the boundary type it stands in for
200
+ (the screenshot manifest's `seed` steps), so only the container is checked here — exactly as
201
+ much as the remote it replaces would have checked before handing its JSON over. */
191
202
  return value as T[];
192
203
  }
193
204
 
194
- function requiredArg<T>(args: AutomationArgs, key: string): T {
205
+ function requiredArg<T>(args: CommandArgValues, key: string): T {
195
206
  const value = args[key];
196
- if (value === null || typeof value !== "object") {
207
+ if (!isNonNullObject(value)) {
197
208
  throw new TypeError(`seed argument "${key}" must be an object`);
198
209
  }
210
+ /* SAFETY: as in `arrayArg`: a fixture written against the boundary type it stands in for, of
211
+ which only the object container is checked here. */
199
212
  return value as T;
200
213
  }
201
214
 
202
- function optionalString(args: AutomationArgs, key: string): string | undefined {
215
+ function optionalString(args: CommandArgValues, key: string): string | undefined {
203
216
  const value = args[key];
204
217
  if (value === undefined) {
205
218
  return undefined;
206
219
  }
207
- if (typeof value !== "string") {
220
+ if (!isString(value)) {
208
221
  throw new TypeError(`seed argument "${key}" must be a string`);
209
222
  }
210
223
  return value;
@@ -216,7 +229,9 @@ function optionalString(args: AutomationArgs, key: string): string | undefined {
216
229
  * Each one writes exactly what its named boundary would have written, and nothing else — the git
217
230
  * seed does not also open the Source Control panel, because a user does that.
218
231
  */
219
- export function createSeeds(deps: AutomationDeps): SeedDefinition[] {
232
+ export function createSeeds(
233
+ deps: Pick<AutomationDeps, "seedAssistantMessages" | "seedPublishConnected">,
234
+ ): SeedDefinition[] {
220
235
  return [
221
236
  {
222
237
  boundary: "the assistant's model stream",
@@ -252,10 +267,13 @@ export function createSeeds(deps: AutomationDeps): SeedDefinition[] {
252
267
  id: "seed.publish",
253
268
  run: (args) => {
254
269
  const accountId = optionalString(args, "accountId");
255
- deps.seedPublishConnected({
270
+ const connected: Parameters<AutomationDeps["seedPublishConnected"]>[0] = {
256
271
  deployment: requiredArg<PagesDeploymentInfo>(args, "deployment"),
257
- ...(accountId ? { accountId } : {}),
258
- });
272
+ };
273
+ if (accountId) {
274
+ connected.accountId = accountId;
275
+ }
276
+ deps.seedPublishConnected(connected);
259
277
  },
260
278
  },
261
279
  {
@@ -264,9 +282,16 @@ export function createSeeds(deps: AutomationDeps): SeedDefinition[] {
264
282
  run: (args) => {
265
283
  // The working tree really is a remote here: the git-panel shot photographs whatever the
266
284
  // Author happened to have dirty, because its project lives inside this repository.
267
- shell.git.status = (args.status as GitStatusResult | undefined) ?? null;
268
- shell.git.branches = (args.branches as GitBranchesResult | undefined) ?? null;
269
- shell.git.logEntries = (args.log as GitLogEntry[] | undefined) ?? null;
285
+ /* SAFETY: as in `arrayArg`: a fixture written against the platform's git route answers it
286
+ stands in for, passed on as the route's JSON would have been, unchecked. */
287
+ const { status, branches, log } = args as {
288
+ status?: GitStatusResult;
289
+ branches?: GitBranchesResult;
290
+ log?: GitLogEntry[];
291
+ };
292
+ shell.git.status = status ?? null;
293
+ shell.git.branches = branches ?? null;
294
+ shell.git.logEntries = log ?? null;
270
295
  shell.git.loading = false;
271
296
  shell.git.error = null;
272
297
  render();
@@ -293,12 +318,9 @@ export function createSeeds(deps: AutomationDeps): SeedDefinition[] {
293
318
  * its `run`, never while building it, so the no-op deps below can never be called.
294
319
  */
295
320
  export function seedIds(): string[] {
296
- const inert = {
297
- registry: undefined as unknown as CommandRegistry,
298
- seedAssistantMessages: () => {},
299
- seedPublishConnected: () => {},
300
- } satisfies AutomationDeps;
301
- return createSeeds(inert).map((seed) => seed.id);
321
+ return createSeeds({ seedAssistantMessages: () => {}, seedPublishConnected: () => {} }).map(
322
+ (seed) => seed.id,
323
+ );
302
324
  }
303
325
 
304
326
  // ─── The API ──────────────────────────────────────────────────────────────────
@@ -340,8 +362,8 @@ export interface AutomationProbe {
340
362
  }
341
363
 
342
364
  export interface AutomationApi {
343
- run: (id: string, args?: AutomationArgs) => Promise<void>;
344
- seed: (id: string, args?: AutomationArgs) => Promise<void>;
365
+ run: (id: string, args?: CommandArgValues) => Promise<void>;
366
+ seed: (id: string, args?: CommandArgValues) => Promise<void>;
345
367
  probe: AutomationProbe;
346
368
  }
347
369
 
@@ -391,7 +413,7 @@ function unknownCommandMessage(
391
413
  if (seeds.has(id)) {
392
414
  return `"${id}" is a seed, not a command — call seed("${id}", …)`;
393
415
  }
394
- const gap = AUTOMATION_COMMANDS[id];
416
+ const gap = COMMAND_GAPS.get(id);
395
417
  if (gap?.disposition === "refused") {
396
418
  return `"${id}" is refused by spec §13.5: ${gap.note}`;
397
419
  }
@@ -435,7 +457,7 @@ export function createAutomationApi(deps: AutomationDeps): AutomationApi {
435
457
  },
436
458
  async seed(id, args = {}) {
437
459
  const bare = id.startsWith("seed.") ? id.slice(5) : id;
438
- const refusal = REFUSED_SEEDS[bare];
460
+ const refusal = SEED_REFUSALS.get(bare);
439
461
  if (refusal) {
440
462
  throw new AutomationRefusedError(
441
463
  id,
@@ -453,6 +475,11 @@ export function createAutomationApi(deps: AutomationDeps): AutomationApi {
453
475
  };
454
476
  }
455
477
 
478
+ declare global {
479
+ /** The automation hook, installed only on a page load that opted in with `?automation=1`. */
480
+ var __jxAutomation: AutomationApi | undefined;
481
+ }
482
+
456
483
  /** The hook is opt-in per page load: only `?automation=1` installs it. */
457
484
  export function shouldInstallAutomation(search: string): boolean {
458
485
  return new URLSearchParams(search).get("automation") === "1";
@@ -466,6 +493,6 @@ export function installAutomationHook(deps: AutomationDeps): boolean {
466
493
  if (!shouldInstallAutomation(location.search)) {
467
494
  return false;
468
495
  }
469
- (globalThis as Record<string, unknown>).__jxAutomation = createAutomationApi(deps);
496
+ globalThis.__jxAutomation = createAutomationApi(deps);
470
497
  return true;
471
498
  }