@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
@@ -2,15 +2,17 @@
2
2
  * Project-path.ts — the containment check the assistant's file tools run before they touch disk.
3
3
  *
4
4
  * `ai.md` §4: a file tool refuses a path outside the open project itself, rather than leaving the
5
- * server to. `list_files`, `read_file` and `write_file` always refused one; `create_component`
6
- * and `create_page` took the model's path as given and handed it to the platform write. One module,
7
- * so the two sets of tools cannot disagree about what "inside the project" means, and a leaf,
8
- * because the document tools and the project tools already import each other's neighbours.
5
+ * server to. `list_files`, `read_file` and `write_file` always refused one; `create_component` and
6
+ * `create_page` took the model's path as given and handed it to the platform write. One module, so
7
+ * the two sets of tools cannot disagree about what "inside the project" means, and a leaf, because
8
+ * the document tools and the project tools already import each other's neighbours.
9
9
  *
10
- * @docs studio/ai/chat
11
10
  * @license MIT
11
+ * @docs studio/ai/chat
12
12
  */
13
13
 
14
+ import { isString } from "@jxsuite/schema/guards";
15
+ import type { JsonValue } from "@jxsuite/schema/types";
14
16
  import type { ToolResult } from "@jxsuite/ai/tools";
15
17
 
16
18
  /**
@@ -18,11 +20,12 @@ import type { ToolResult } from "@jxsuite/ai/tools";
18
20
  * `..` segments, drive letters, a home directory). The server re-checks; this keeps the error
19
21
  * actionable.
20
22
  *
21
- * @param {unknown} path
23
+ * @param {JsonValue | undefined} path A tool argument as the model sent it — any JSON value, or
24
+ * absent.
22
25
  * @returns {string | null}
23
26
  */
24
- export function normalizeRelPath(path: unknown): string | null {
25
- if (typeof path !== "string" || !path.trim()) {
27
+ export function normalizeRelPath(path: JsonValue | undefined): string | null {
28
+ if (!isString(path) || !path.trim()) {
26
29
  return null;
27
30
  }
28
31
  let p = path.trim().replaceAll("\\", "/");
@@ -42,10 +45,10 @@ export function normalizeRelPath(path: unknown): string | null {
42
45
  * The refusal a tool returns for a path {@link normalizeRelPath} rejected, quoting what the model
43
46
  * sent so it can see what to change.
44
47
  *
45
- * @param {unknown} path
48
+ * @param {JsonValue | undefined} path The tool argument as the model sent it.
46
49
  * @returns {ToolResult}
47
50
  */
48
- export function invalidPathResult(path: unknown): ToolResult {
51
+ export function invalidPathResult(path: JsonValue | undefined): ToolResult {
49
52
  return {
50
53
  success: false,
51
54
  error: `Invalid path ${JSON.stringify(path)} — use a path relative to the project root (no leading "/", no "..").`,
Binary file
@@ -3,10 +3,10 @@
3
3
  *
4
4
  * After a mutation passes schema validation, this module attempts a lightweight headless render
5
5
  * (buildScope → renderNode into a throwaway div) and reports render-time errors back through the
6
- * same { ok, error } shape that applyAndValidate consumes. The model can then self-correct
7
- * within the round budget instead of the user discovering a blank canvas.
6
+ * same { ok, error } shape that applyAndValidate consumes. The model can then self-correct within
7
+ * the round budget instead of the user discovering a blank canvas.
8
8
  *
9
- * v1 scope: catches render throws only (missing $ref, malformed Function body, bad template
9
+ * V1 scope: catches render throws only (missing $ref, malformed Function body, bad template
10
10
  * expressions). Does NOT detect empty/zero-node output or deep-render custom element internals
11
11
  * (connectedCallback doesn't fire on detached nodes).
12
12
  *
@@ -19,11 +19,12 @@ import type { JxDocument } from "@jxsuite/schema/types";
19
19
  /**
20
20
  * Translate a render-time error into an actionable message the model can fix.
21
21
  *
22
- * @param {Error} err
22
+ * @param {unknown} cause What the render threw — an Error in practice; anything else is printed
23
+ * as-is.
23
24
  * @returns {string}
24
25
  */
25
- function translateRenderError(err: Error): string {
26
- const msg = err.message || String(err);
26
+ function translateRenderError(cause: unknown): string {
27
+ const msg = (cause instanceof Error && cause.message) || String(cause);
27
28
 
28
29
  if (msg.includes("is not defined") || msg.includes("Cannot read properties of")) {
29
30
  return `Render error: ${msg}\n → Fix: A $ref or template expression references a name that doesn't exist in state. Check that all $ref paths and \${...} expressions match entries in the document's "state" object.`;
@@ -64,7 +65,7 @@ export async function renderCheck(
64
65
 
65
66
  return { ok: true };
66
67
  } catch (error) {
67
- return { ok: false, error: translateRenderError(error as Error) };
68
+ return { ok: false, error: translateRenderError(error) };
68
69
  } finally {
69
70
  // Dispose all effects created synchronously by renderNode via the RUNTIME's runScoped — scope
70
71
  // Collection is per @vue/reactivity module instance, so a studio effectScope here would collect
@@ -35,13 +35,22 @@ import type { SettingsPatch } from "./write-queue";
35
35
  /** The synchronous source of truth. Absent key means unset — which is not the same as `""`. */
36
36
  const values = new Map<string, string>();
37
37
 
38
+ /**
39
+ * The cache, when this realm has one. `lib.dom` declares `localStorage` unconditionally, but a
40
+ * realm without a DOM (Bun under test, a worker) has none — so it is looked up on every use, inside
41
+ * the caller's `try`, where an access that throws (storage disabled) is already handled.
42
+ */
43
+ function cacheStorage(): Storage | undefined {
44
+ return typeof localStorage === "undefined" ? undefined : localStorage;
45
+ }
46
+
38
47
  /** Mirror a value into the cache, so the next boot is correct before the backend answers. */
39
48
  function writeCache(key: string, value: string | null): void {
40
49
  try {
41
50
  if (value === null) {
42
- globalThis.localStorage?.removeItem(key);
51
+ cacheStorage()?.removeItem(key);
43
52
  } else {
44
- globalThis.localStorage?.setItem(key, value);
53
+ cacheStorage()?.setItem(key, value);
45
54
  }
46
55
  } catch {
47
56
  /* Storage unavailable (private mode) — the Map still serves this session. */
@@ -60,7 +69,7 @@ function writeCache(key: string, value: string | null): void {
60
69
  */
61
70
  try {
62
71
  for (const definition of ALL_SETTINGS) {
63
- const cached = globalThis.localStorage?.getItem(definition.key);
72
+ const cached = cacheStorage()?.getItem(definition.key);
64
73
  if (cached !== null && cached !== undefined) {
65
74
  values.set(definition.key, cached);
66
75
  }
@@ -120,7 +129,7 @@ function announce(keys: readonly string[]): void {
120
129
  // ─── Writing ──────────────────────────────────────────────────────────────────
121
130
 
122
131
  const queue = createWriteQueue({
123
- onError(error: unknown) {
132
+ onError(error) {
124
133
  notify("error", "Your settings could not be saved.", {
125
134
  detail: error instanceof Error ? error.message : String(error),
126
135
  key: "settings-write",
@@ -2,18 +2,18 @@
2
2
  * A coalescing, serializing write queue.
3
3
  *
4
4
  * The defect it exists to make unrepresentable: saving a provider mutates three settings through
5
- * three setters, and each setter used to fire its own whole-map write. Three overlapping writes went
6
- * out against one file, each reading storage at a different moment, with no ordering between them —
7
- * so whichever landed last won. That was observed in the wild as a settings file holding
5
+ * three setters, and each setter used to fire its own whole-map write. Three overlapping writes
6
+ * went out against one file, each reading storage at a different moment, with no ordering between
7
+ * them — so whichever landed last won. That was observed in the wild as a settings file holding
8
8
  * `{"jx.ai.model": "gpt-4o"}`: the SECOND of three snapshots, landing last, a state storage itself
9
9
  * never rested in.
10
10
  *
11
11
  * Two rules, and they are different guarantees:
12
12
  *
13
- * 1. **Coalesce.** Every mutation in one synchronous burst merges into a single patch, sent once
14
- * the burst has finished. N setters produce one write, not N.
15
- * 2. **Serialize.** At most one send is in flight. A mutation made while one is out waits for it
16
- * rather than racing it, so the order the app made changes in is the order the store sees them.
13
+ * 1. **Coalesce.** Every mutation in one synchronous burst merges into a single patch, sent once the
14
+ * burst has finished. N setters produce one write, not N.
15
+ * 2. **Serialize.** At most one send is in flight. A mutation made while one is out waits for it
16
+ * rather than racing it, so the order the app made changes in is the order the store sees them.
17
17
  *
18
18
  * Generic over the transport so the kernel can hand it a platform call and a test can hand it an
19
19
  * array. `schedule` is injectable for the same reason.
@@ -34,7 +34,7 @@ export interface WriteQueueOptions {
34
34
  /** Deliver one merged patch. Rejection is reported through {@link WriteQueueOptions.onError}. */
35
35
  send: (patch: SettingsPatch) => Promise<void>;
36
36
  /** Called with the failure and the patch that did not land. */
37
- onError?: (error: unknown, patch: SettingsPatch) => void;
37
+ onError?: (cause: unknown, patch: SettingsPatch) => void;
38
38
  /**
39
39
  * Defer to the end of the current burst. Defaults to `queueMicrotask`.
40
40
  *
@@ -89,7 +89,7 @@ export function createWriteQueue(opts: WriteQueueOptions): WriteQueue {
89
89
  }
90
90
  tail = tail
91
91
  .then(() => opts.send(patch))
92
- .catch((error: unknown) => {
92
+ .catch((error) => {
93
93
  opts.onError?.(error, patch);
94
94
  });
95
95
  return tail;
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { JxMutableNode } from "@jxsuite/schema/types";
9
- import { displayTagName } from "@jxsuite/schema/guards";
9
+ import { displayTagName, isNonNullObject, isString } from "@jxsuite/schema/guards";
10
10
 
11
11
  interface TokenLintFinding {
12
12
  path: string;
@@ -25,7 +25,8 @@ interface TokenLintFinding {
25
25
  function buildTokenIndex(projectStyle: Record<string, string>) {
26
26
  const index = new Map<string, string>();
27
27
  for (const [key, value] of Object.entries(projectStyle)) {
28
- if (!key.startsWith("--") || typeof value !== "string") {
28
+ // The style object comes from `project.json`, where a key can also hold a nested block.
29
+ if (!key.startsWith("--") || !isString(value)) {
29
30
  continue;
30
31
  }
31
32
  const norm = value.toLowerCase().trim();
@@ -43,7 +44,7 @@ function buildTokenIndex(projectStyle: Record<string, string>) {
43
44
  * @returns {boolean}
44
45
  */
45
46
  function isTokenRef(value: string) {
46
- return typeof value === "string" && value.includes("var(--");
47
+ return value.includes("var(--");
47
48
  }
48
49
 
49
50
  /**
@@ -53,7 +54,7 @@ function isTokenRef(value: string) {
53
54
  * @returns {boolean}
54
55
  */
55
56
  function isTemplate(value: string) {
56
- return typeof value === "string" && value.includes("${");
57
+ return value.includes("${");
57
58
  }
58
59
 
59
60
  /**
@@ -78,18 +79,19 @@ export function flagHardcodedTokens(
78
79
 
79
80
  const findings: TokenLintFinding[] = [];
80
81
 
81
- function walk(node: unknown, pathPrefix: string) {
82
- if (!node || typeof node !== "object") {
82
+ /* Every member is re-checked rather than trusted: callers hand over model output parsed from
83
+ JSON, so a "node" may be a primitive, a `style` may be a string, and a child may be anything. */
84
+ function walk(el: JxMutableNode, pathPrefix: string) {
85
+ if (!isNonNullObject(el)) {
83
86
  return;
84
87
  }
85
- const el = node as JxMutableNode;
86
88
 
87
- if (el.style && typeof el.style === "object") {
89
+ if (isNonNullObject(el.style)) {
88
90
  for (const [prop, val] of Object.entries(el.style)) {
89
91
  if (prop.startsWith("@")) {
90
92
  continue;
91
93
  }
92
- if (typeof val !== "string") {
94
+ if (!isString(val)) {
93
95
  continue;
94
96
  }
95
97
  if (isTokenRef(val) || isTemplate(val)) {
@@ -112,7 +114,7 @@ export function flagHardcodedTokens(
112
114
  if (Array.isArray(el.children)) {
113
115
  for (let i = 0; i < el.children.length; i++) {
114
116
  const child = el.children[i];
115
- if (child && typeof child === "object") {
117
+ if (isNonNullObject(child)) {
116
118
  walk(child, `${pathPrefix} > ${displayTagName(child.tagName) || `[${i}]`}`);
117
119
  }
118
120
  }
@@ -20,7 +20,7 @@
20
20
 
21
21
  import type { createChatState } from "@jxsuite/ai/chat-state";
22
22
  import { DEFAULT_TURN_POLICY, runTurn } from "@jxsuite/ai/harness";
23
- import type { TurnRun } from "@jxsuite/ai/harness";
23
+ import type { TurnInput, TurnRun } from "@jxsuite/ai/harness";
24
24
  import { toChatMessages, toOpenAITools } from "@jxsuite/ai/messages";
25
25
  import type { StreamingClient } from "@jxsuite/ai/streaming-client";
26
26
  import { createSessionFacts } from "@jxsuite/ai/tools";
@@ -36,6 +36,9 @@ import { studioTurnHooks } from "./harness/turn-hooks";
36
36
  /** What a turn that drew nothing says: the model answered with neither text nor a tool call. */
37
37
  export const EMPTY_TURN_TEXT = DEFAULT_TURN_POLICY.emptyText;
38
38
 
39
+ /** {@link TurnInput} while this module assembles it: read-only to `runTurn`, not to its builder. */
40
+ type TurnInputDraft = { -readonly [K in keyof TurnInput]: TurnInput[K] };
41
+
39
42
  interface RunAgentLoopOptions {
40
43
  chatState: ReturnType<typeof createChatState>;
41
44
  streamingClient: StreamingClient;
@@ -94,7 +97,7 @@ export async function runAgentLoop({
94
97
  let superseded = false;
95
98
  let run: TurnRun | undefined;
96
99
  try {
97
- run = runTurn({
100
+ const input: TurnInputDraft = {
98
101
  history,
99
102
  system: [{ text: systemPrompt }],
100
103
  /* Projected from the chat store, the transcript of record. The streaming client is read on
@@ -104,13 +107,15 @@ export async function runAgentLoop({
104
107
  chatState.toMessagesArray(),
105
108
  toOpenAITools(request.tools),
106
109
  systemPrompt,
110
+ /* SAFETY: the one production caller, `document-assistant.ts`, always passes its turn
111
+ controller's signal; only tests that drive the loop directly omit it, and their stream
112
+ doubles record the absent signal rather than reading it — which the agent-trace
113
+ goldens (`signal: "none"`) pin. */
107
114
  signal as AbortSignal,
108
115
  ),
109
116
  modelInfo: { family: "openai-compat", model: chatState.model },
110
117
  tools: toolRegistry,
111
- ...(signal ? { signal } : {}),
112
118
  turnId: ledger.turnId,
113
- ...(placeholder ? { firstMessageId: placeholder.id } : {}),
114
119
  policy: { estimateTokens: estimatePromptTokens },
115
120
  hooks: studioTurnHooks({
116
121
  superseded: () =>
@@ -128,7 +133,14 @@ export async function runAgentLoop({
128
133
  applyHarnessEvent(chatState, event);
129
134
  }
130
135
  },
131
- });
136
+ };
137
+ if (signal) {
138
+ input.signal = signal;
139
+ }
140
+ if (placeholder) {
141
+ input.firstMessageId = placeholder.id;
142
+ }
143
+ run = runTurn(input);
132
144
  await run.outcome;
133
145
  } finally {
134
146
  endBatch();
@@ -26,23 +26,43 @@
26
26
  * @docs studio/ai/chat
27
27
  */
28
28
 
29
- import { isSealContent } from "@jxsuite/ai/messages";
29
+ import { SEAL_RELOADED, isSealContent } from "@jxsuite/ai/messages";
30
30
  import type { ToolResult } from "@jxsuite/ai/tools";
31
+ import { isBoolean, isNonNullObject, isString } from "@jxsuite/schema/guards";
31
32
  import type { PersistedMessage } from "./ai-session-store";
32
- import { UNANSWERED_TOOL_RESULT } from "./context-manager";
33
33
 
34
34
  /** The tool that suspends a turn on the author (services/ai-ask.ts). */
35
- const ASK_TOOL = "ask_user";
35
+ export const ASK_TOOL = "ask_user";
36
36
 
37
- /** The outcome of an ordinary call that never ran to completion — the seal's own words. */
38
- const NEVER_COMPLETED = JSON.parse(UNANSWERED_TOOL_RESULT) as ToolResult;
37
+ /**
38
+ * The outcome of an ordinary call that never ran to completion — the seal's own words: the object
39
+ * `context-manager.ts`'s `UNANSWERED_TOOL_RESULT` serializes, built from the same sentence.
40
+ */
41
+ const NEVER_COMPLETED: ToolResult = { success: false, error: SEAL_RELOADED };
39
42
 
40
- /** A tool-call record as persisted: `id` and `name` are what pairing and the chip read. */
43
+ /**
44
+ * A tool-call record as persisted: `id` and `name` are what pairing and the chip read. Every member
45
+ * is optional and unchecked, because the records come back out of storage; each is narrowed where
46
+ * it is read.
47
+ */
41
48
  interface PersistedToolCall {
42
49
  id?: unknown;
43
50
  name?: unknown;
44
51
  result?: unknown;
45
- [key: string]: unknown;
52
+ }
53
+
54
+ /**
55
+ * Whether a persisted `toolCalls` entry is a record at all. Any object qualifies — every member of
56
+ * {@link PersistedToolCall} is optional — and a primitive (a corrupt or foreign payload) is passed
57
+ * through untouched by both directions.
58
+ */
59
+ function isToolCallRecord(value: unknown): value is PersistedToolCall {
60
+ return isNonNullObject(value);
61
+ }
62
+
63
+ /** Whether a parsed tool message is a `ToolResult`: an object whose `success` is a boolean. */
64
+ function isToolResult(value: unknown): value is ToolResult {
65
+ return isNonNullObject(value) && "success" in value && isBoolean(value.success);
46
66
  }
47
67
 
48
68
  /**
@@ -61,28 +81,29 @@ export function stripToolResults(messages: readonly PersistedMessage[]): Persist
61
81
  return {
62
82
  ...message,
63
83
  toolCalls: message.toolCalls.map((call) => {
64
- if (!call || typeof call !== "object") {
84
+ if (!isToolCallRecord(call)) {
65
85
  return call;
66
86
  }
67
- const { result: _result, ...rest } = call as PersistedToolCall;
87
+ const { result: _result, ...rest } = call;
68
88
  return rest;
69
89
  }),
70
90
  };
71
91
  });
72
92
  }
73
93
 
74
- /** A tool message's content as a `ToolResult`, or null when it is not one. */
75
- function parseToolResult(content: unknown): ToolResult | null {
76
- if (typeof content !== "string") {
94
+ /**
95
+ * A tool message's content as a `ToolResult`, or null when it is not one.
96
+ *
97
+ * The content is re-checked as a string although {@link PersistedMessage} declares one: the message
98
+ * came back out of storage, where a corrupt or foreign payload can hold anything.
99
+ */
100
+ function parseToolResult(content: string): ToolResult | null {
101
+ if (!isString(content)) {
77
102
  return null;
78
103
  }
79
104
  try {
80
- const parsed = JSON.parse(content) as unknown;
81
- return parsed &&
82
- typeof parsed === "object" &&
83
- typeof (parsed as ToolResult).success === "boolean"
84
- ? (parsed as ToolResult)
85
- : null;
105
+ const parsed: unknown = JSON.parse(content);
106
+ return isToolResult(parsed) ? parsed : null;
86
107
  } catch {
87
108
  return null;
88
109
  }
@@ -114,7 +135,7 @@ export function backfillToolResults(messages: readonly PersistedMessage[]): Pers
114
135
  break;
115
136
  }
116
137
  const result = parseToolResult(reply.content);
117
- if (typeof reply.toolCallId === "string" && result && !replies.has(reply.toolCallId)) {
138
+ if (isString(reply.toolCallId) && result && !replies.has(reply.toolCallId)) {
118
139
  replies.set(reply.toolCallId, result);
119
140
  if (isSealContent(reply.content)) {
120
141
  sealed.add(reply.toolCallId);
@@ -123,12 +144,11 @@ export function backfillToolResults(messages: readonly PersistedMessage[]): Pers
123
144
  }
124
145
  return {
125
146
  ...message,
126
- toolCalls: message.toolCalls.map((call) => {
127
- if (!call || typeof call !== "object") {
128
- return call;
147
+ toolCalls: message.toolCalls.map((record) => {
148
+ if (!isToolCallRecord(record)) {
149
+ return record;
129
150
  }
130
- const record = call as PersistedToolCall;
131
- const id = typeof record.id === "string" ? record.id : undefined;
151
+ const id = isString(record.id) ? record.id : undefined;
132
152
  const answered = id === undefined ? undefined : replies.get(id);
133
153
  if (record.name === ASK_TOOL) {
134
154
  /* A question's only outcomes are an answer or none: a seal is not an answer, and a
@@ -22,6 +22,20 @@
22
22
  * @docs studio/interface/problems-and-progress
23
23
  */
24
24
 
25
+ /**
26
+ * A W3C `TrustedHTML`: opaque to script, accepted by an injection sink, and stringifying to the
27
+ * markup it wraps. This TypeScript's `lib.dom` does not declare it, so it is declared here with the
28
+ * one member a reader can rely on.
29
+ */
30
+ export interface TrustedHtml {
31
+ toString: () => string;
32
+ }
33
+
34
+ /** The policy object `createPolicy` answers with, narrowed to the one factory the shell calls. */
35
+ export interface StudioPolicy {
36
+ createHTML: (input: string) => TrustedHtml;
37
+ }
38
+
25
39
  /** The subset of the Trusted Types API this module uses — typed here so no DOM lib is required. */
26
40
  interface TrustedTypesApi {
27
41
  createPolicy: (
@@ -31,7 +45,7 @@ interface TrustedTypesApi {
31
45
  createScript?: (input: string) => string;
32
46
  createScriptURL?: (input: string) => string;
33
47
  },
34
- ) => { createHTML: (input: string) => unknown };
48
+ ) => StudioPolicy;
35
49
  }
36
50
 
37
51
  /** The policy name, which a CSP `trusted-types` directive would have to allow. */
@@ -75,18 +89,21 @@ export function assertSanitized(value: string): string {
75
89
  }
76
90
 
77
91
  /** Created once. A second `createPolicy` with the same name throws when policies are restricted. */
78
- let policy: { createHTML: (input: string) => unknown } | null = null;
92
+ let policy: StudioPolicy | null = null;
79
93
 
80
94
  /**
81
95
  * The shell's Trusted Types policy, or null where the API does not exist.
82
96
  *
83
- * @returns {{ createHTML: (input: string) => unknown } | null}
97
+ * @returns {StudioPolicy | null}
84
98
  */
85
- export function studioPolicy(): { createHTML: (input: string) => unknown } | null {
99
+ export function studioPolicy(): StudioPolicy | null {
86
100
  if (policy) {
87
101
  return policy;
88
102
  }
89
- const api = (globalThis as unknown as { trustedTypes?: TrustedTypesApi }).trustedTypes;
103
+ /* SAFETY: `trustedTypes` is the member Trusted Types adds to the global scope, which this
104
+ `lib.dom` predates; the intersection only names it, typed as possibly absent, and an absent
105
+ member (a browser without Trusted Types, and the tests) is the `undefined` handled below. */
106
+ const api = (globalThis as typeof globalThis & { trustedTypes?: TrustedTypesApi }).trustedTypes;
90
107
  if (!api) {
91
108
  return null;
92
109
  }
@@ -110,9 +127,9 @@ export function studioPolicy(): { createHTML: (input: string) => unknown } | nul
110
127
  * guard that only fires under Trusted Types would be a guard that never fires in the tests.
111
128
  *
112
129
  * @param {string} value Markup from `markdownToHtml`.
113
- * @returns {unknown} A `TrustedHTML`, or the asserted string.
130
+ * @returns {TrustedHtml | string} A `TrustedHTML`, or the asserted string.
114
131
  */
115
- export function trustedHtml(value: string): unknown {
132
+ export function trustedHtml(value: string): TrustedHtml | string {
116
133
  const active = studioPolicy();
117
134
  return active ? active.createHTML(value) : assertSanitized(value);
118
135
  }
@@ -76,6 +76,12 @@ export interface ContextEntry {
76
76
  kind: ContextKind;
77
77
  }
78
78
 
79
+ /** A `$media` map, split: the base width, and every other entry classified. */
80
+ export interface ContextSplit {
81
+ base: string;
82
+ entries: ContextEntry[];
83
+ }
84
+
79
85
  /**
80
86
  * Which kind of context an entry is.
81
87
  *
@@ -98,12 +104,9 @@ export function contextKindOf(query: string): ContextKind {
98
104
  * Split a `$media` map into the base width and the three context groups.
99
105
  *
100
106
  * @param {Record<string, string> | undefined} media
101
- * @returns {{ base: string; entries: ContextEntry[] }}
107
+ * @returns {ContextSplit}
102
108
  */
103
- export function splitContexts(media?: Record<string, string> | undefined): {
104
- base: string;
105
- entries: ContextEntry[];
106
- } {
109
+ export function splitContexts(media?: Record<string, string> | undefined): ContextSplit {
107
110
  const source = media ?? {};
108
111
  const entries: ContextEntry[] = [];
109
112
  for (const [key, raw] of Object.entries(source)) {
@@ -232,11 +235,11 @@ export function contextsError(container: HTMLElement): { target: string; message
232
235
  * a projection, which makes reading through to the store the thing that keeps them honest.
233
236
  */
234
237
  function currentConfig(): ProjectConfig {
235
- return (projectState?.projectConfig || {}) as ProjectConfig;
238
+ return projectState?.projectConfig ?? {};
236
239
  }
237
240
 
238
241
  function currentMedia(): Record<string, string> {
239
- return (currentConfig().$media || {}) as Record<string, string>;
242
+ return currentConfig().$media ?? {};
240
243
  }
241
244
 
242
245
  // ─── Writing ──────────────────────────────────────────────────────────────────
@@ -271,7 +274,7 @@ async function persistMedia(
271
274
  target: ErrorTarget,
272
275
  ): Promise<void> {
273
276
  const config = currentConfig();
274
- const candidate = { ...config, $media: next } as unknown;
277
+ const candidate: ProjectConfig = { ...config, $media: next };
275
278
  let schemaErrors: string[] = [];
276
279
  let inherited: string[] = [];
277
280
  try {