@jxsuite/studio 6.1.0 → 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 (645) hide show
  1. package/dist/chunks/2020-f2gkpy8d.js +4 -0
  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-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
  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-5g0ag7c0.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-pxg4ap1e.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-qbj760tx.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-anyrgzvb.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-v2bvmbjj.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-txjjzrsm.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-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-cpxkgjrj.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-y64hrt8p.js +12 -0
  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-sf49ee9x.js +14 -0
  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 +98 -98
  140. package/dist/workers/ts.worker.js +3 -3
  141. package/package.json +11 -11
  142. package/src/about/about-modal.ts +4 -3
  143. package/src/account/action-flow.ts +45 -38
  144. package/src/account-status.ts +7 -2
  145. package/src/browse/library-layouts.ts +8 -5
  146. package/src/browse/library-model.ts +18 -6
  147. package/src/browse/library-pane.ts +37 -21
  148. package/src/browse/library-preview.ts +14 -9
  149. package/src/browse/library-source.ts +1 -1
  150. package/src/canvas/asset-refs.ts +24 -9
  151. package/src/canvas/asset-resolve.ts +19 -23
  152. package/src/canvas/canvas-helpers.ts +7 -6
  153. package/src/canvas/canvas-live-render.ts +44 -53
  154. package/src/canvas/canvas-patcher.ts +30 -30
  155. package/src/canvas/canvas-perf.ts +11 -5
  156. package/src/canvas/canvas-render.ts +66 -42
  157. package/src/canvas/canvas-surface.ts +5 -3
  158. package/src/canvas/canvas-utils.ts +163 -64
  159. package/src/canvas/dialog-path.ts +9 -4
  160. package/src/canvas/dialog-state.ts +1 -2
  161. package/src/canvas/diff-marks.ts +9 -16
  162. package/src/canvas/diff-toolbar.ts +8 -7
  163. package/src/canvas/edit-width-drag.ts +4 -1
  164. package/src/canvas/edit-width.ts +1 -3
  165. package/src/canvas/iframe-channel.ts +27 -13
  166. package/src/canvas/iframe-drop.ts +13 -12
  167. package/src/canvas/iframe-editable-root.ts +29 -16
  168. package/src/canvas/iframe-entry.ts +80 -63
  169. package/src/canvas/iframe-eval.ts +73 -49
  170. package/src/canvas/iframe-host.ts +203 -118
  171. package/src/canvas/iframe-inline-edit.ts +69 -32
  172. package/src/canvas/iframe-insert.ts +5 -4
  173. package/src/canvas/iframe-interaction.ts +37 -26
  174. package/src/canvas/iframe-overlay.ts +1 -1
  175. package/src/canvas/iframe-patch.ts +18 -15
  176. package/src/canvas/iframe-position.ts +12 -6
  177. package/src/canvas/iframe-protocol.ts +15 -16
  178. package/src/canvas/iframe-render.ts +41 -36
  179. package/src/canvas/iframe-slash.ts +24 -11
  180. package/src/canvas/iframe-subtree.ts +6 -2
  181. package/src/canvas/path-mapping.ts +19 -12
  182. package/src/canvas/popover-path.ts +7 -3
  183. package/src/canvas/popover-state.ts +1 -2
  184. package/src/canvas/serialize-scope.ts +13 -5
  185. package/src/canvas/stage-scrollbar.ts +2 -1
  186. package/src/canvas/surface-registry.ts +21 -3
  187. package/src/collab/collab-commands.ts +7 -2
  188. package/src/collab/collab-session.ts +84 -45
  189. package/src/collab/collab-state.ts +4 -3
  190. package/src/collab/monaco-binding.ts +16 -13
  191. package/src/collab/monaco-cursors.ts +5 -2
  192. package/src/commands/budget.ts +3 -3
  193. package/src/commands/command-args.ts +103 -71
  194. package/src/commands/context.ts +22 -20
  195. package/src/commands/defaults.ts +4 -1
  196. package/src/commands/keymap.ts +47 -43
  197. package/src/commands/levels.ts +3 -3
  198. package/src/commands/live-context.ts +10 -8
  199. package/src/commands/reference.ts +2 -1
  200. package/src/commands/registry.ts +12 -10
  201. package/src/commands/run-reported.ts +15 -10
  202. package/src/component-props.ts +46 -30
  203. package/src/content/collection-match.ts +5 -4
  204. package/src/content/draft-state.ts +4 -3
  205. package/src/content/entry-commands.ts +3 -2
  206. package/src/content/entry-editor.ts +29 -17
  207. package/src/content/entry-fields.ts +12 -7
  208. package/src/content/entry-model.ts +21 -12
  209. package/src/editor/canvas-context-menu.ts +1 -2
  210. package/src/editor/canvas-slash-bridge.ts +3 -6
  211. package/src/editor/content-slice.ts +16 -14
  212. package/src/editor/context-menu.ts +35 -22
  213. package/src/editor/convert-targets.ts +30 -35
  214. package/src/editor/convert-to-component.ts +11 -5
  215. package/src/editor/convert-to-repeater.ts +34 -22
  216. package/src/editor/editable-tags.ts +17 -2
  217. package/src/editor/file-drop-action.ts +21 -22
  218. package/src/editor/inline-edit-apply.ts +35 -17
  219. package/src/editor/inline-edit.ts +66 -50
  220. package/src/editor/inline-format.ts +59 -56
  221. package/src/editor/inline-link.ts +40 -15
  222. package/src/editor/insert-zone-action.ts +1 -1
  223. package/src/editor/merge-tags.ts +58 -19
  224. package/src/editor/repeater-scope.ts +39 -28
  225. package/src/editor/shortcuts.ts +87 -47
  226. package/src/editor/slash-menu.ts +1 -6
  227. package/src/files/asset-versions.ts +4 -4
  228. package/src/files/components.ts +15 -10
  229. package/src/files/elements.ts +5 -6
  230. package/src/files/file-ops.ts +77 -36
  231. package/src/files/files.ts +90 -95
  232. package/src/files/media-meta.ts +2 -1
  233. package/src/files/media-paths.ts +6 -1
  234. package/src/files/serialize-document.ts +2 -2
  235. package/src/format/constraints.ts +1 -1
  236. package/src/format/convert-file.ts +27 -13
  237. package/src/format/format-choices.ts +2 -1
  238. package/src/format/format-host.ts +76 -50
  239. package/src/github/github-auth-status.ts +27 -3
  240. package/src/github/github-auth.ts +19 -9
  241. package/src/github/github-publish.ts +24 -20
  242. package/src/grid/cell-editors.ts +46 -31
  243. package/src/grid/cell-popovers.ts +5 -3
  244. package/src/grid/edit-buffer.ts +10 -9
  245. package/src/grid/grid-controller.ts +20 -22
  246. package/src/grid/grid-layout.ts +21 -5
  247. package/src/grid/grid-open.ts +3 -6
  248. package/src/grid/grid-panel.ts +11 -4
  249. package/src/grid/grid-source.ts +8 -8
  250. package/src/grid/grid-view.ts +14 -17
  251. package/src/grid/redirects-grid.ts +14 -5
  252. package/src/grid/redirects.ts +16 -14
  253. package/src/grid/schema-columns.ts +25 -19
  254. package/src/grid/sources/connector-source.ts +47 -20
  255. package/src/grid/sources/content-source.ts +25 -24
  256. package/src/grid/sources/csv-file-source.ts +2 -2
  257. package/src/grid/tabulator-tables.d.ts +55 -34
  258. package/src/hosting/stage.ts +7 -7
  259. package/src/i18n/i18n-commands.ts +1 -2
  260. package/src/media/media-pane.ts +4 -1
  261. package/src/new-project/add-repo-modal.ts +20 -19
  262. package/src/new-project/import-tab.ts +10 -14
  263. package/src/new-project/location-fields.ts +2 -1
  264. package/src/new-project/new-project-modal.ts +12 -9
  265. package/src/packages/jxsuite-update.ts +4 -3
  266. package/src/packages/pull-package-sync.ts +26 -25
  267. package/src/page-params.ts +97 -68
  268. package/src/panels/activity-panel.ts +17 -9
  269. package/src/panels/ai-chat/attached-context.ts +13 -7
  270. package/src/panels/ai-chat/chat-view.ts +80 -73
  271. package/src/panels/ai-chat/composer.ts +30 -33
  272. package/src/panels/ai-chat/sessions-view.ts +1 -2
  273. package/src/panels/ai-panel.ts +23 -20
  274. package/src/panels/block-action-bar.ts +46 -35
  275. package/src/panels/bottom-dock.ts +5 -3
  276. package/src/panels/canvas-dnd-bridge.ts +31 -24
  277. package/src/panels/data-explorer.ts +62 -25
  278. package/src/panels/data-grid.ts +14 -11
  279. package/src/panels/dnd.ts +108 -118
  280. package/src/panels/editors.ts +55 -22
  281. package/src/panels/elements-panel.ts +10 -3
  282. package/src/panels/events-panel.ts +84 -69
  283. package/src/panels/formula-workspace.ts +76 -51
  284. package/src/panels/frontmatter-fields.ts +24 -19
  285. package/src/panels/frontmatter-panel.ts +44 -34
  286. package/src/panels/git-diff-open.ts +4 -4
  287. package/src/panels/git-panel.ts +49 -61
  288. package/src/panels/head-panel.ts +131 -111
  289. package/src/panels/i18n-panel.ts +10 -3
  290. package/src/panels/imports-panel.ts +23 -47
  291. package/src/panels/jump-bar.ts +48 -29
  292. package/src/panels/layers-panel.ts +97 -74
  293. package/src/panels/left-panel.ts +3 -3
  294. package/src/panels/pane-context.ts +31 -22
  295. package/src/panels/pane-grid.ts +49 -20
  296. package/src/panels/panel-registry.ts +22 -37
  297. package/src/panels/properties-panel.ts +175 -121
  298. package/src/panels/quick-search.ts +53 -31
  299. package/src/panels/right-panel.ts +3 -3
  300. package/src/panels/seo-modal.ts +13 -17
  301. package/src/panels/settings-menu.ts +15 -15
  302. package/src/panels/signals-panel.ts +153 -131
  303. package/src/panels/statement-editor.ts +230 -140
  304. package/src/panels/style-panel.ts +254 -216
  305. package/src/panels/style-utils.ts +114 -51
  306. package/src/panels/stylebook-doc.ts +57 -54
  307. package/src/panels/stylebook-layers-panel.ts +9 -9
  308. package/src/panels/stylebook-panel.ts +13 -17
  309. package/src/panels/tab-drop.ts +27 -11
  310. package/src/panels/tab-strip.ts +36 -26
  311. package/src/platform-errors.ts +57 -43
  312. package/src/platform.ts +58 -30
  313. package/src/platforms/cloud.ts +345 -175
  314. package/src/platforms/default-platform.ts +10 -4
  315. package/src/platforms/devserver.ts +174 -127
  316. package/src/platforms/read-batcher.ts +16 -8
  317. package/src/project-list.ts +2 -1
  318. package/src/publish/deploy-checklist.ts +8 -2
  319. package/src/publish/pages-service.ts +28 -13
  320. package/src/publish/publish-commands.ts +5 -4
  321. package/src/publish/publish-panel.ts +10 -6
  322. package/src/recent-projects.ts +15 -8
  323. package/src/resize-edges.ts +26 -36
  324. package/src/services/a11y-report.ts +26 -19
  325. package/src/services/agent-seed.ts +23 -11
  326. package/src/services/ai-ask.ts +9 -12
  327. package/src/services/ai-command-tools.ts +68 -62
  328. package/src/services/ai-import-tools.ts +80 -67
  329. package/src/services/ai-models.ts +17 -13
  330. package/src/services/ai-project-tools.ts +68 -32
  331. package/src/services/ai-session-store.ts +19 -10
  332. package/src/services/ai-system-prompt.ts +46 -20
  333. package/src/services/ai-tools.ts +71 -27
  334. package/src/services/ai-write-report.ts +20 -12
  335. package/src/services/ai-writes.ts +4 -4
  336. package/src/services/automation.ts +58 -31
  337. package/src/services/cem-export.ts +149 -58
  338. package/src/services/clock.ts +6 -1
  339. package/src/services/code-services.ts +37 -31
  340. package/src/services/context-manager.ts +14 -10
  341. package/src/services/context-resolver.ts +20 -8
  342. package/src/services/data-service.ts +19 -15
  343. package/src/services/directory-picker.ts +18 -12
  344. package/src/services/document-assistant.ts +39 -19
  345. package/src/services/gated-registry.ts +10 -6
  346. package/src/services/harness/chat-reducer.ts +23 -1
  347. package/src/services/import-client.ts +91 -38
  348. package/src/services/import-seed.ts +8 -2
  349. package/src/services/jx-validate.ts +28 -31
  350. package/src/services/live-preview.ts +0 -0
  351. package/src/services/live-surfaces.ts +6 -3
  352. package/src/services/model-uri.ts +10 -2
  353. package/src/services/module-preloads.ts +12 -8
  354. package/src/services/monaco-buffer.ts +43 -24
  355. package/src/services/monaco-lazy.ts +7 -8
  356. package/src/services/monaco-setup.ts +23 -16
  357. package/src/services/notify.ts +44 -17
  358. package/src/services/popover-report.ts +25 -10
  359. package/src/services/preview-eval.ts +20 -8
  360. package/src/services/profile.ts +13 -6
  361. package/src/services/project-path.ts +13 -10
  362. package/src/services/references.ts +0 -0
  363. package/src/services/render-critic.ts +8 -7
  364. package/src/services/settings/kernel.ts +13 -4
  365. package/src/services/settings/write-queue.ts +9 -9
  366. package/src/services/token-lint.ts +12 -10
  367. package/src/services/tool-executor.ts +17 -5
  368. package/src/services/tool-outcomes.ts +44 -24
  369. package/src/services/trusted-types.ts +24 -7
  370. package/src/settings/contexts-section.ts +11 -8
  371. package/src/settings/contributed-section.ts +79 -60
  372. package/src/settings/css-vars-editor.ts +37 -16
  373. package/src/settings/defs-editor.ts +38 -35
  374. package/src/settings/extension-rows.ts +16 -8
  375. package/src/settings/extension-sections.ts +23 -13
  376. package/src/settings/extensions-section.ts +4 -1
  377. package/src/settings/general-settings.ts +11 -8
  378. package/src/settings/locales-section.ts +20 -12
  379. package/src/settings/preferences-dialog.ts +9 -6
  380. package/src/settings/preferences-keymap.ts +7 -5
  381. package/src/settings/preferences-sections.ts +11 -5
  382. package/src/settings/project-sections.ts +1 -1
  383. package/src/settings/schema-field-ui.ts +9 -0
  384. package/src/settings/settings-document.ts +5 -5
  385. package/src/shell/tree.ts +6 -5
  386. package/src/shell.ts +104 -81
  387. package/src/site-context.ts +37 -22
  388. package/src/state.ts +41 -49
  389. package/src/store.ts +54 -34
  390. package/src/studio.ts +39 -77
  391. package/src/style/live-preview.ts +1 -1
  392. package/src/style/project-styles.ts +6 -7
  393. package/src/style/token-ref.ts +5 -4
  394. package/src/surfaces/about.ts +18 -19
  395. package/src/surfaces/add-repo.ts +17 -19
  396. package/src/surfaces/ai-chat.ts +31 -36
  397. package/src/surfaces/ai-credentials-form.ts +6 -16
  398. package/src/surfaces/ai-managed-connect.ts +3 -4
  399. package/src/surfaces/ai-model-picker.ts +3 -5
  400. package/src/surfaces/block-action-bar.ts +22 -11
  401. package/src/surfaces/boot-failure.ts +4 -5
  402. package/src/surfaces/bottom-dock.ts +9 -18
  403. package/src/surfaces/canvas-stage.ts +12 -11
  404. package/src/surfaces/cf-account-picker.ts +17 -18
  405. package/src/surfaces/commandbar.ts +14 -9
  406. package/src/surfaces/convert-repeater.ts +17 -19
  407. package/src/surfaces/data-actions.ts +9 -7
  408. package/src/surfaces/dialog.ts +26 -28
  409. package/src/surfaces/diff-toolbar.ts +9 -7
  410. package/src/surfaces/doc-header.ts +10 -19
  411. package/src/surfaces/empty-state.ts +7 -10
  412. package/src/surfaces/entry-editor.ts +14 -11
  413. package/src/surfaces/expression-editor.ts +11 -25
  414. package/src/surfaces/files-panel.ts +27 -14
  415. package/src/surfaces/formula-palette.ts +4 -5
  416. package/src/surfaces/git-panel.ts +7 -15
  417. package/src/surfaces/github-auth.ts +16 -20
  418. package/src/surfaces/github-publish.ts +17 -22
  419. package/src/surfaces/grid-cell.ts +30 -31
  420. package/src/surfaces/grid-open.ts +10 -14
  421. package/src/surfaces/grid-panel.ts +13 -9
  422. package/src/surfaces/grid-replace.ts +13 -13
  423. package/src/surfaces/grid-views.ts +15 -18
  424. package/src/surfaces/inspector-dock.ts +13 -12
  425. package/src/surfaces/jump-bar.ts +5 -6
  426. package/src/surfaces/jxsuite-update.ts +16 -22
  427. package/src/surfaces/library-pane.ts +25 -20
  428. package/src/surfaces/logic-panel.ts +17 -30
  429. package/src/surfaces/logic-workspace.ts +13 -15
  430. package/src/surfaces/media-browser.ts +11 -10
  431. package/src/surfaces/media-field.ts +4 -5
  432. package/src/surfaces/media-pane.ts +8 -7
  433. package/src/surfaces/menu.ts +29 -23
  434. package/src/surfaces/navigator-dock.ts +11 -12
  435. package/src/surfaces/new-project.ts +27 -26
  436. package/src/surfaces/pane-context.ts +20 -25
  437. package/src/surfaces/pane-grid.ts +15 -10
  438. package/src/surfaces/panel-activity.ts +5 -6
  439. package/src/surfaces/panel-data.ts +3 -4
  440. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  441. package/src/surfaces/panel-elements.ts +5 -7
  442. package/src/surfaces/panel-i18n.ts +5 -7
  443. package/src/surfaces/panel-imports.ts +6 -13
  444. package/src/surfaces/panel-outline.ts +25 -19
  445. package/src/surfaces/panel-page.ts +11 -18
  446. package/src/surfaces/panel-problems.ts +5 -7
  447. package/src/surfaces/panel-signals.ts +20 -34
  448. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  449. package/src/surfaces/preferences.ts +21 -11
  450. package/src/surfaces/progress-modal.ts +15 -9
  451. package/src/surfaces/properties-panel.json +1 -1
  452. package/src/surfaces/properties-panel.ts +20 -42
  453. package/src/surfaces/publish.ts +18 -18
  454. package/src/surfaces/push-plan.ts +7 -8
  455. package/src/surfaces/rail.json +126 -73
  456. package/src/surfaces/rail.ts +38 -12
  457. package/src/surfaces/reference-field.ts +11 -15
  458. package/src/surfaces/schema-builder.ts +16 -22
  459. package/src/surfaces/schema-form.ts +15 -25
  460. package/src/surfaces/secret-field.ts +9 -6
  461. package/src/surfaces/seo.ts +21 -15
  462. package/src/surfaces/settings-contexts.ts +9 -7
  463. package/src/surfaces/settings-contributed.ts +14 -10
  464. package/src/surfaces/settings-css-vars.ts +5 -12
  465. package/src/surfaces/settings-defs.json +2 -2
  466. package/src/surfaces/settings-defs.ts +17 -21
  467. package/src/surfaces/settings-deploy.ts +8 -15
  468. package/src/surfaces/settings-extensions.ts +5 -6
  469. package/src/surfaces/settings-head.ts +33 -39
  470. package/src/surfaces/settings-locales.ts +8 -20
  471. package/src/surfaces/settings-overview.ts +5 -6
  472. package/src/surfaces/settings-packages.ts +8 -7
  473. package/src/surfaces/settings-pane.ts +9 -18
  474. package/src/surfaces/settings-rawjson.ts +5 -6
  475. package/src/surfaces/shell.ts +1 -2
  476. package/src/surfaces/slash-menu.ts +19 -9
  477. package/src/surfaces/statements.ts +13 -18
  478. package/src/surfaces/statusbar.ts +17 -14
  479. package/src/surfaces/style-panel.ts +18 -31
  480. package/src/surfaces/stylebook-chrome.ts +3 -5
  481. package/src/surfaces/tab-strip.ts +14 -13
  482. package/src/surfaces/target-line.ts +6 -7
  483. package/src/surfaces/welcome.ts +5 -7
  484. package/src/tabs/patch-ops.ts +4 -3
  485. package/src/tabs/project-config.ts +32 -21
  486. package/src/tabs/selection.ts +36 -8
  487. package/src/tabs/tab.ts +52 -41
  488. package/src/tabs/transact.ts +98 -53
  489. package/src/tabs/typing.ts +31 -0
  490. package/src/types.ts +32 -17
  491. package/src/ui/ai-credentials-form.ts +10 -13
  492. package/src/ui/ai-model-picker.ts +3 -3
  493. package/src/ui/cf-account-picker.ts +7 -9
  494. package/src/ui/color-selector.ts +9 -5
  495. package/src/ui/dynamic-slot.ts +7 -8
  496. package/src/ui/expression-editor.ts +112 -105
  497. package/src/ui/form-controls.ts +57 -48
  498. package/src/ui/formula-catalog.ts +239 -230
  499. package/src/ui/formula-chips.ts +33 -18
  500. package/src/ui/layers.ts +44 -31
  501. package/src/ui/media-picker.ts +18 -9
  502. package/src/ui/popover-surface.ts +20 -12
  503. package/src/ui/progress-modal.ts +13 -8
  504. package/src/ui/regions.ts +7 -6
  505. package/src/ui/schema-form.ts +113 -70
  506. package/src/ui/surface.ts +71 -8
  507. package/src/ui/timing.ts +9 -0
  508. package/src/ui/value-source.ts +44 -31
  509. package/src/ui/virtual-window.ts +3 -2
  510. package/src/utils/base64.ts +3 -1
  511. package/src/utils/edit-display.ts +103 -74
  512. package/src/utils/element-selectors.ts +3 -2
  513. package/src/utils/google-fonts.ts +15 -14
  514. package/src/utils/inherited-style.ts +18 -20
  515. package/src/utils/link-target.ts +1 -1
  516. package/src/utils/preview-format.ts +25 -3
  517. package/src/utils/strip-events.ts +49 -22
  518. package/src/utils/studio-utils.ts +29 -14
  519. package/src/view.ts +2 -3
  520. package/src/workspace/pane-derive.ts +10 -12
  521. package/src/workspace/session.ts +53 -43
  522. package/src/workspace/workspace.ts +47 -36
  523. package/dist/chunks/2020-nkxms0ay.js +0 -4
  524. package/dist/chunks/adapter-m948ab5f.js +0 -4
  525. package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
  526. package/dist/chunks/cf-settings-356xdtne.js +0 -4
  527. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  528. package/dist/chunks/color-field-embq5ctg.js +0 -4
  529. package/dist/chunks/color-fpezvnkt.js +0 -4
  530. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  531. package/dist/chunks/combobox-773hdzyj.js +0 -4
  532. package/dist/chunks/components-yk3t844e.js +0 -4
  533. package/dist/chunks/content-source-bawmyc09.js +0 -4
  534. package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
  535. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  536. package/dist/chunks/editor-6sc8nacq.js +0 -4
  537. package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
  538. package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
  539. package/dist/chunks/file-ops-gye0qw56.js +0 -4
  540. package/dist/chunks/files-dmc2xvcq.js +0 -4
  541. package/dist/chunks/format-host-t76b53f8.js +0 -4
  542. package/dist/chunks/fs-events-cg4tpz06.js +0 -4
  543. package/dist/chunks/git-panel-yef7bshy.js +0 -4
  544. package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
  545. package/dist/chunks/icons-qbh8akb1.js +0 -4
  546. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  547. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  548. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  549. package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
  550. package/dist/chunks/index-nag78a9h.js +0 -4
  551. package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
  552. package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
  553. package/dist/chunks/layers-fvz99859.js +0 -4
  554. package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
  555. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  556. package/dist/chunks/lit-html-9agdspkt.js +0 -4
  557. package/dist/chunks/media-picker-rhjvyy00.js +0 -4
  558. package/dist/chunks/menu-2e4y9j7b.js +0 -4
  559. package/dist/chunks/menu-37d07z9m.js +0 -4
  560. package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
  561. package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
  562. package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
  563. package/dist/chunks/notify-h3www560.js +0 -4
  564. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  565. package/dist/chunks/parse-897fvqah.js +0 -4
  566. package/dist/chunks/platform-hz34wcd7.js +0 -4
  567. package/dist/chunks/popover-8htra4er.js +0 -4
  568. package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
  569. package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
  570. package/dist/chunks/references-2cgdxnb8.js +0 -4
  571. package/dist/chunks/right-panel-jf856w5w.js +0 -4
  572. package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
  573. package/dist/chunks/select-n3v7gwas.js +0 -4
  574. package/dist/chunks/split-pff8f3ze.js +0 -4
  575. package/dist/chunks/studio-0f55h9ye.js +0 -5
  576. package/dist/chunks/studio-0sqdhnew.js +0 -12
  577. package/dist/chunks/studio-19x1c75w.js +0 -5
  578. package/dist/chunks/studio-2sqcndak.js +0 -5
  579. package/dist/chunks/studio-3aey7dd3.js +0 -5
  580. package/dist/chunks/studio-3bpdkq2s.js +0 -5
  581. package/dist/chunks/studio-47y6fbpf.js +0 -5
  582. package/dist/chunks/studio-4m3826v2.js +0 -5
  583. package/dist/chunks/studio-4nx2dj1g.js +0 -4
  584. package/dist/chunks/studio-4xv5s47r.js +0 -9
  585. package/dist/chunks/studio-5g4t8v6w.js +0 -5
  586. package/dist/chunks/studio-5py436sf.js +0 -5
  587. package/dist/chunks/studio-77kt594t.js +0 -5
  588. package/dist/chunks/studio-8f87n763.js +0 -10
  589. package/dist/chunks/studio-8mb00b84.js +0 -5
  590. package/dist/chunks/studio-8p51gq2h.js +0 -6
  591. package/dist/chunks/studio-954ds834.js +0 -5
  592. package/dist/chunks/studio-9ft45c83.js +0 -9
  593. package/dist/chunks/studio-a2138x5k.js +0 -7
  594. package/dist/chunks/studio-a9yzstqj.js +0 -5
  595. package/dist/chunks/studio-acdksxx6.js +0 -5
  596. package/dist/chunks/studio-ar8jcf2y.js +0 -5
  597. package/dist/chunks/studio-bmn4mn9j.js +0 -7
  598. package/dist/chunks/studio-e7xxa0sj.js +0 -5
  599. package/dist/chunks/studio-ecaz25vk.js +0 -5
  600. package/dist/chunks/studio-ery42sqr.js +0 -4
  601. package/dist/chunks/studio-fzdywr6p.js +0 -9
  602. package/dist/chunks/studio-g5fmf0c1.js +0 -5
  603. package/dist/chunks/studio-g7nse7zb.js +0 -5
  604. package/dist/chunks/studio-geq1ea6k.js +0 -14
  605. package/dist/chunks/studio-ghkb32r8.js +0 -5
  606. package/dist/chunks/studio-ghrhy2y7.js +0 -5
  607. package/dist/chunks/studio-grawhey1.js +0 -5
  608. package/dist/chunks/studio-h0xgswew.js +0 -5
  609. package/dist/chunks/studio-h9c4p2tx.js +0 -5
  610. package/dist/chunks/studio-jyzj5cxs.js +0 -5
  611. package/dist/chunks/studio-mgx8yhnz.js +0 -64
  612. package/dist/chunks/studio-mpb04y1d.js +0 -6
  613. package/dist/chunks/studio-n17mty64.js +0 -5
  614. package/dist/chunks/studio-nwh2eqsk.js +0 -6
  615. package/dist/chunks/studio-q1h883bt.js +0 -16
  616. package/dist/chunks/studio-q4tv82h7.js +0 -9
  617. package/dist/chunks/studio-qpqa7vk3.js +0 -5
  618. package/dist/chunks/studio-qqz8e5gk.js +0 -5
  619. package/dist/chunks/studio-qvasen3f.js +0 -5
  620. package/dist/chunks/studio-rggdb3hm.js +0 -5
  621. package/dist/chunks/studio-sghy936h.js +0 -4
  622. package/dist/chunks/studio-skprc6ef.js +0 -5
  623. package/dist/chunks/studio-tt2nactf.js +0 -5
  624. package/dist/chunks/studio-tyasmc39.js +0 -5
  625. package/dist/chunks/studio-vk9ezads.js +0 -5
  626. package/dist/chunks/studio-vzacdfsc.js +0 -4
  627. package/dist/chunks/studio-w4c0xmrw.js +0 -5
  628. package/dist/chunks/studio-wfjqhhbk.js +0 -5
  629. package/dist/chunks/studio-wgh5kxpj.js +0 -5
  630. package/dist/chunks/studio-xasj0796.js +0 -5
  631. package/dist/chunks/studio-y78s8r2n.js +0 -5
  632. package/dist/chunks/studio-z8w183sh.js +0 -5
  633. package/dist/chunks/studio-zscd9ty4.js +0 -928
  634. package/dist/chunks/studio-zxp13sss.js +0 -7
  635. package/dist/chunks/studio-zygnmm01.js +0 -5
  636. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  637. package/dist/chunks/tabs-jwthg40w.js +0 -4
  638. package/dist/chunks/textfield-spy3hc77.js +0 -4
  639. package/dist/chunks/toast-4d35zd64.js +0 -4
  640. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  641. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  642. package/dist/chunks/tree-h19v1jfz.js +0 -4
  643. package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
  644. package/dist/chunks/workspace-m15qtcqp.js +0 -4
  645. package/dist/chunks/ws-client-nf61frr1.js +0 -4
@@ -32,6 +32,7 @@
32
32
  */
33
33
 
34
34
  import { LOCATION_ID_FILE } from "@jxsuite/protocol/routes";
35
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
35
36
  import { errorMessage } from "@jxsuite/schema/parse";
36
37
 
37
38
  /** Re-exported so a caller wiring up `locate` need not also reach into the protocol package. */
@@ -57,11 +58,20 @@ type ShowDirectoryPicker = (opts?: {
57
58
  startIn?: string;
58
59
  }) => Promise<DirectoryHandle>;
59
60
 
61
+ /** A realm that exposes the File System Access API's folder chooser. */
62
+ type DirectoryPickerRealm = typeof globalThis & { showDirectoryPicker: ShowDirectoryPicker };
63
+
64
+ /**
65
+ * Whether a realm carries `showDirectoryPicker`. The DOM lib this package compiles against does not
66
+ * declare it (the API is Chromium-only), so the global is probed rather than read.
67
+ */
68
+ function hasDirectoryPicker(realm: typeof globalThis): realm is DirectoryPickerRealm {
69
+ return "showDirectoryPicker" in realm && typeof realm.showDirectoryPicker === "function";
70
+ }
71
+
60
72
  /** Whether this browser can open a native folder chooser at all. */
61
73
  export function canPickDirectory(): boolean {
62
- return (
63
- typeof (globalThis as { showDirectoryPicker?: unknown }).showDirectoryPicker === "function"
64
- );
74
+ return hasDirectoryPicker(globalThis);
65
75
  }
66
76
 
67
77
  /** A location id: URL-safe, unguessable enough that a concurrent pick cannot collide. */
@@ -76,13 +86,8 @@ function newLocationId(): string {
76
86
  * `showDirectoryPicker`, a test double) is not `instanceof Error` here, but it still says what it
77
87
  * is.
78
88
  */
79
- function nameOf(error: unknown): string {
80
- return typeof error === "object" &&
81
- error !== null &&
82
- "name" in error &&
83
- typeof error.name === "string"
84
- ? error.name
85
- : "";
89
+ function nameOf(cause: unknown): string {
90
+ return isNonNullObject(cause) && "name" in cause && isString(cause.name) ? cause.name : "";
86
91
  }
87
92
 
88
93
  /**
@@ -111,12 +116,13 @@ function nameOf(error: unknown): string {
111
116
  export async function pickDirectoryPath(
112
117
  locate: (query: { name: string; id: string }) => Promise<string | null>,
113
118
  ): Promise<string | null> {
114
- const show = (globalThis as { showDirectoryPicker?: ShowDirectoryPicker }).showDirectoryPicker;
115
- if (typeof show !== "function") {
119
+ const realm = globalThis;
120
+ if (!hasDirectoryPicker(realm)) {
116
121
  throw new TypeError(
117
122
  "This browser has no folder chooser. Type the folder's path into Location instead.",
118
123
  );
119
124
  }
125
+ const show = realm.showDirectoryPicker;
120
126
 
121
127
  let handle: DirectoryHandle;
122
128
  try {
@@ -42,6 +42,7 @@ import { getBaseUrl, getOpenAiKey } from "./ai-settings";
42
42
  import { preferredModel } from "./ai-models";
43
43
  import { pruneOrphanToolMessages, trimContext } from "./context-manager";
44
44
  import { renderCheck } from "./render-critic";
45
+ import type { CandidateDocument, RenderVerdict } from "./ai-write-report";
45
46
  import { validateDoc } from "./jx-validate";
46
47
  import { reloadFileInTab } from "../files/files";
47
48
  import { getExtensionCatalog, refreshExtensionUi } from "../format/format-host";
@@ -59,6 +60,20 @@ function projectRoot() {
59
60
  return workspace.projectRoot || "";
60
61
  }
61
62
 
63
+ /**
64
+ * The open project's configuration.
65
+ *
66
+ * @returns {ProjectConfig | null}
67
+ */
68
+ function projectConfig(): ProjectConfig | null {
69
+ return workspace.projectConfig;
70
+ }
71
+
72
+ /* SAFETY: renderCheck runs the whole render inside a try and answers `{ ok: false, error }` for
73
+ anything it cannot render, so JSON that is not (yet) a valid document is exactly what it is safe
74
+ to hand; its JxDocument parameter names what renders, not what may be probed. */
75
+ const probeRender = renderCheck as (doc: CandidateDocument) => Promise<RenderVerdict>;
76
+
62
77
  /**
63
78
  * Create a document-assistant session bound to the currently active tab.
64
79
  *
@@ -82,8 +97,10 @@ export function createDocumentAssistant() {
82
97
  `ctx.session`. New Chat starts over; a new session id keeps what the conversation knew. */
83
98
  let sessionFacts = createSessionFacts();
84
99
 
85
- const getProjectStyle = () =>
86
- (workspace.projectConfig as ProjectConfig | null)?.style as Record<string, string> | undefined;
100
+ /* SAFETY: the token tools read only the top-level `--*` keys of the project style block, and skip
101
+ any whose value is not a string, so the nested rule blocks a JxStyle may also hold are never
102
+ read as tokens. */
103
+ const getProjectStyle = () => projectConfig()?.style as Record<string, string> | undefined;
87
104
 
88
105
  const findOpenTab = (path: string): Tab | null => {
89
106
  for (const tab of workspace.tabs.values()) {
@@ -106,9 +123,7 @@ export function createDocumentAssistant() {
106
123
  const plat = getPlatform();
107
124
  await plat.writeFile(relPath, content);
108
125
  },
109
- renderCheck: renderCheck as (
110
- doc: unknown,
111
- ) => Promise<{ ok: true } | { ok: false; error: string }>,
126
+ renderCheck: probeRender,
112
127
  getProjectStyle,
113
128
  findOpenTab,
114
129
  reloadTab: reloadFileInTab,
@@ -126,9 +141,7 @@ export function createDocumentAssistant() {
126
141
  });
127
142
  registerProjectTools(innerRegistry, {
128
143
  getTab: () => activeTab.value,
129
- renderCheck: renderCheck as (
130
- doc: unknown,
131
- ) => Promise<{ ok: true } | { ok: false; error: string }>,
144
+ renderCheck: probeRender,
132
145
  getProjectStyle,
133
146
  findOpenTab,
134
147
  reloadTab: reloadFileInTab,
@@ -221,9 +234,7 @@ export function createDocumentAssistant() {
221
234
  const commandTools = createCommandToolRegistry({
222
235
  getProjectStyle,
223
236
  getTab: () => activeTab.value,
224
- renderCheck: renderCheck as (
225
- doc: unknown,
226
- ) => Promise<{ ok: true } | { ok: false; error: string }>,
237
+ renderCheck: probeRender,
227
238
  validate: validateDoc,
228
239
  });
229
240
  const toolRegistry = composeToolRegistries(
@@ -263,16 +274,21 @@ export function createDocumentAssistant() {
263
274
  be two answers to "what can this project turn on". */
264
275
  const catalog: ExtensionCatalogSummary[] = [];
265
276
  for (const entry of getExtensionCatalog()) {
266
- catalog.push({
277
+ const summary: ExtensionCatalogSummary = {
267
278
  name: entry.name,
268
279
  sections: entry.sections.map((section) => section.key),
269
- ...(entry.title === undefined ? {} : { title: entry.title }),
270
- ...(entry.description === undefined ? {} : { description: entry.description }),
271
- });
280
+ };
281
+ if (entry.title !== undefined) {
282
+ summary.title = entry.title;
283
+ }
284
+ if (entry.description !== undefined) {
285
+ summary.description = entry.description;
286
+ }
287
+ catalog.push(summary);
272
288
  }
273
289
  return buildSystemPrompt({
274
290
  document: tab ? toRaw(tab.doc.document) : undefined,
275
- projectConfig: (workspace.projectConfig as ProjectConfig | null) || undefined,
291
+ projectConfig: projectConfig() || undefined,
276
292
  components: componentRegistry.length > 0 ? componentRegistry : undefined,
277
293
  projectRoot: workspace.projectRoot || undefined,
278
294
  hasProject: Boolean(workspace.projectRoot),
@@ -285,8 +301,9 @@ export function createDocumentAssistant() {
285
301
  /* Read per turn from the live registry — a projected tool the gate will honour this round is
286
302
  listed this round, and one it will not is not. */
287
303
  commandTools: commandToolBlurbs(activeRegistry()),
288
- ...(inventory && inventory.length > 0 ? { fileInventory: inventory } : {}),
289
- ...(catalog.length > 0 ? { extensionCatalog: catalog } : {}),
304
+ // Absent and undefined read the same: every option is destructured without a default.
305
+ fileInventory: inventory && inventory.length > 0 ? inventory : undefined,
306
+ extensionCatalog: catalog.length > 0 ? catalog : undefined,
290
307
  });
291
308
  }
292
309
 
@@ -347,7 +364,7 @@ export function createDocumentAssistant() {
347
364
  baseUrl: getBaseUrl() || undefined,
348
365
  /* The persisted conversation, so the backend can keep its rounds on one warm prompt cache.
349
366
  Sent to the backend only, which hashes it before any provider sees it (specs/ai.md §2.5). */
350
- sessionId: sessionId ?? undefined,
367
+ sessionId,
351
368
  });
352
369
 
353
370
  if (sessionFacts.sessionId !== sessionId) {
@@ -480,6 +497,9 @@ export function createDocumentAssistant() {
480
497
  */
481
498
  function pushRestoredMessages(msgs: sessionStore.PersistedMessage[]) {
482
499
  for (const m of backfillToolResults(msgs)) {
500
+ /* SAFETY: every persisted message was written by persistChat from a live message (its role,
501
+ tool calls and timestamp included) and its call results were restored by
502
+ backfillToolResults above; only the id a legacy entry may lack is synthesized here. */
483
503
  chatState.messages.push({
484
504
  ...m,
485
505
  id: m.id || `restored_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
@@ -13,7 +13,7 @@
13
13
  * @license MIT
14
14
  */
15
15
 
16
- import type { ToolContext, ToolDefinition, ToolRegistry } from "@jxsuite/ai/tools";
16
+ import type { ToolArguments, ToolContext, ToolDefinition, ToolRegistry } from "@jxsuite/ai/tools";
17
17
 
18
18
  export interface ToolAvailability {
19
19
  /** Whether the tool is currently advertised/executable. */
@@ -48,17 +48,21 @@ export function createGatedToolRegistry(
48
48
  },
49
49
  listForLLM() {
50
50
  const available = new Set(this.list().map((t) => t.name));
51
- return inner
52
- .listForLLM()
53
- .filter((t) => available.has((t as { function?: { name?: string } }).function?.name ?? ""));
51
+ return inner.listForLLM().filter((t) => {
52
+ /* SAFETY: a @jxsuite/ai registry lists each tool in OpenAI function-calling form,
53
+ `{ type: "function", function: { name, … } }`; the registry interface types the entries
54
+ as bare objects, and the optional chain still answers "" for any other shape. */
55
+ const tool = t as { function?: { name?: string } };
56
+ return available.has(tool.function?.name ?? "");
57
+ });
54
58
  },
55
59
  getDefinition(toolName: string) {
56
60
  return inner.getDefinition(toolName);
57
61
  },
58
- validate(toolName: string, args: object) {
62
+ validate(toolName: string, args: ToolArguments) {
59
63
  return inner.validate(toolName, args);
60
64
  },
61
- async execute(toolName: string, args: object, ctx?: ToolContext) {
65
+ async execute(toolName: string, args: ToolArguments, ctx?: ToolContext) {
62
66
  if (inner.getDefinition(toolName) && !isAvailable(toolName)) {
63
67
  const gate = availability.get(toolName);
64
68
  return {
@@ -11,11 +11,30 @@
11
11
 
12
12
  import type { createChatState } from "@jxsuite/ai/chat-state";
13
13
  import type { HarnessEvent, TurnOutcome } from "@jxsuite/ai/harness";
14
+ import { isJsonObject, isNumber, isString } from "@jxsuite/schema/guards";
14
15
  import type { ImportProgressEvent } from "../../types";
15
16
  import { recordImportProgress } from "../import-run";
16
17
 
17
18
  type ChatStore = ReturnType<typeof createChatState>;
18
19
 
20
+ /**
21
+ * Whether a tool's progress payload is an import progress line. The engine carries progress as
22
+ * opaque JSON; only the import tool reports any, and only in this shape. Exported so the test
23
+ * harness's tool context records exactly what this reducer records.
24
+ */
25
+ export function isImportProgressEvent(value: unknown): value is ImportProgressEvent {
26
+ if (!isJsonObject(value)) {
27
+ return false;
28
+ }
29
+ const { phase, message, current, total } = value;
30
+ return (
31
+ isString(phase) &&
32
+ isString(message) &&
33
+ (current === undefined || isNumber(current)) &&
34
+ (total === undefined || isNumber(total))
35
+ );
36
+ }
37
+
19
38
  /** How a turn's end reads in the transcript: the cap message, an error row, or nothing more. */
20
39
  function applyOutcome(chat: ChatStore, outcome: TurnOutcome): void {
21
40
  switch (outcome.kind) {
@@ -96,7 +115,10 @@ export function applyHarnessEvent(chat: ChatStore, event: HarnessEvent): void {
96
115
  break;
97
116
  }
98
117
  case "tool_progress": {
99
- recordImportProgress(event.callId, event.progress as unknown as ImportProgressEvent);
118
+ // A call that is not an import run has no record to update either way.
119
+ if (isImportProgressEvent(event.progress)) {
120
+ recordImportProgress(event.callId, event.progress);
121
+ }
100
122
  break;
101
123
  }
102
124
  case "tool_result": {
@@ -18,6 +18,7 @@ import type {
18
18
  ImportSiteOptions,
19
19
  ImportSiteSummary,
20
20
  } from "../types";
21
+ import { isJsonObject } from "@jxsuite/schema/guards";
21
22
  import type { ProjectConfig } from "@jxsuite/schema/types";
22
23
 
23
24
  /**
@@ -29,6 +30,34 @@ import type { ProjectConfig } from "@jxsuite/schema/types";
29
30
  */
30
31
  export const IMPORT_WARNING_PHASE = "warning";
31
32
 
33
+ /** The request headers: JSON, plus the caller's AI credentials when it has them. */
34
+ interface ImportRequestHeaders {
35
+ "Content-Type": string;
36
+ "X-Api-Key"?: string;
37
+ "X-Api-Base-URL"?: string;
38
+ }
39
+
40
+ /** The JSON body the import-site route reads; `model` travels as `aiModel`. */
41
+ interface ImportRequestBody {
42
+ url: string;
43
+ directory: string;
44
+ depth: number;
45
+ maxPages: number;
46
+ aiComponents: boolean;
47
+ breakpoints?: ImportSiteOptions["breakpoints"];
48
+ aiModel?: ImportSiteOptions["model"];
49
+ verify?: boolean;
50
+ verifyThreshold?: number;
51
+ verifyMinFidelity?: number;
52
+ }
53
+
54
+ /** What a `done` line settles the stream with. */
55
+ export interface ImportStreamResult {
56
+ root: string;
57
+ config: ProjectConfig;
58
+ result?: ImportSiteSummary;
59
+ }
60
+
32
61
  interface StreamLine {
33
62
  type: string;
34
63
  phase?: string;
@@ -58,8 +87,8 @@ export async function streamImport(
58
87
  onProgress: (evt: ImportProgressEvent) => void,
59
88
  signal?: AbortSignal,
60
89
  onReady?: (evt: ImportReadyEvent) => void,
61
- ): Promise<{ root: string; config: ProjectConfig; result?: ImportSiteSummary }> {
62
- const headers: Record<string, string> = { "Content-Type": "application/json" };
90
+ ): Promise<ImportStreamResult> {
91
+ const headers: ImportRequestHeaders = { "Content-Type": "application/json" };
63
92
  if (opts.apiKey) {
64
93
  headers["X-Api-Key"] = opts.apiKey;
65
94
  }
@@ -67,32 +96,46 @@ export async function streamImport(
67
96
  headers["X-Api-Base-URL"] = opts.baseUrl;
68
97
  }
69
98
 
70
- const res = await fetch(endpoint, {
71
- body: JSON.stringify({
72
- url: opts.url,
73
- directory: opts.directory,
74
- depth: opts.depth,
75
- maxPages: opts.maxPages,
76
- aiComponents: opts.aiComponents,
77
- ...(opts.breakpoints === undefined ? {} : { breakpoints: opts.breakpoints }),
78
- ...(opts.model === undefined ? {} : { aiModel: opts.model }),
79
- ...(opts.verify === undefined ? {} : { verify: opts.verify }),
80
- ...(opts.verifyThreshold === undefined ? {} : { verifyThreshold: opts.verifyThreshold }),
81
- ...(opts.verifyMinFidelity === undefined
82
- ? {}
83
- : { verifyMinFidelity: opts.verifyMinFidelity }),
84
- }),
85
- headers,
99
+ const request: ImportRequestBody = {
100
+ url: opts.url,
101
+ directory: opts.directory,
102
+ depth: opts.depth,
103
+ maxPages: opts.maxPages,
104
+ aiComponents: opts.aiComponents,
105
+ };
106
+ if (opts.breakpoints !== undefined) {
107
+ request.breakpoints = opts.breakpoints;
108
+ }
109
+ if (opts.model !== undefined) {
110
+ request.aiModel = opts.model;
111
+ }
112
+ if (opts.verify !== undefined) {
113
+ request.verify = opts.verify;
114
+ }
115
+ if (opts.verifyThreshold !== undefined) {
116
+ request.verifyThreshold = opts.verifyThreshold;
117
+ }
118
+ if (opts.verifyMinFidelity !== undefined) {
119
+ request.verifyMinFidelity = opts.verifyMinFidelity;
120
+ }
121
+ // The spread is a plain record copy: an interface is not assignable to the `HeadersInit` record.
122
+ const init: RequestInit = {
123
+ body: JSON.stringify(request),
124
+ headers: { ...headers },
86
125
  method: "POST",
87
- ...(signal === undefined ? {} : { signal }),
88
- });
126
+ };
127
+ if (signal !== undefined) {
128
+ init.signal = signal;
129
+ }
130
+ const res = await fetch(endpoint, init);
89
131
 
90
132
  if (!res.ok) {
91
133
  let message = `Import failed (${res.status})`;
92
134
  try {
93
- const body = (await res.json()) as { error?: string };
94
- if (body.error) {
95
- message = body.error;
135
+ const body: unknown = await res.json();
136
+ // `new Error()` stringifies a non-string message, so String() keeps any `error` value's text.
137
+ if (isJsonObject(body) && body.error) {
138
+ message = String(body.error);
96
139
  }
97
140
  } catch {
98
141
  /* Non-JSON error body — keep the status message. */
@@ -106,7 +149,7 @@ export async function streamImport(
106
149
  const reader = res.body.getReader();
107
150
  const decoder = new TextDecoder();
108
151
  let buffer = "";
109
- let result: { root: string; config: ProjectConfig; result?: ImportSiteSummary } | null = null;
152
+ let result: ImportStreamResult | null = null;
110
153
  /*
111
154
  * Lines the parser could not read. Tolerating one is right — an import that ran for two minutes
112
155
  * should not die on a garbled progress line — but doing it *silently* is not: the import then
@@ -115,37 +158,47 @@ export async function streamImport(
115
158
  */
116
159
  let unreadable = 0;
117
160
 
118
- const handleLine = (line: string) => {
161
+ /** Apply one line; a `done` line's result is returned for the read loop to keep. */
162
+ const handleLine = (line: string): ImportStreamResult | undefined => {
119
163
  const trimmed = line.trim();
120
164
  if (!trimmed) {
121
- return;
165
+ return undefined;
122
166
  }
123
167
  let parsed: StreamLine;
124
168
  try {
169
+ /* SAFETY: the import-site route writes every line as JSON.stringify of one stream line
170
+ object with a string `type`, and every other member is optional; each branch below
171
+ compares `type` to a literal and checks the members it reads before using them. */
125
172
  parsed = JSON.parse(trimmed) as StreamLine;
126
173
  } catch {
127
174
  unreadable += 1;
128
- return; // Tolerate a mangled line rather than killing the whole import.
175
+ return undefined; // Tolerate a mangled line rather than killing the whole import.
129
176
  }
130
177
  if (parsed.type === "progress") {
131
- onProgress({
178
+ const progress: ImportProgressEvent = {
132
179
  phase: parsed.phase ?? "",
133
180
  message: parsed.message ?? "",
134
- ...(parsed.current === undefined ? {} : { current: parsed.current }),
135
- ...(parsed.total === undefined ? {} : { total: parsed.total }),
136
- });
181
+ };
182
+ if (parsed.current !== undefined) {
183
+ progress.current = parsed.current;
184
+ }
185
+ if (parsed.total !== undefined) {
186
+ progress.total = parsed.total;
187
+ }
188
+ onProgress(progress);
137
189
  } else if (parsed.type === "ready" && parsed.root !== undefined) {
138
190
  onReady?.({ root: parsed.root });
139
191
  } else if (parsed.type === "done" && parsed.root !== undefined && parsed.config) {
140
- result = {
141
- root: parsed.root,
142
- config: parsed.config,
143
- ...(parsed.result === undefined ? {} : { result: parsed.result }),
144
- };
192
+ const settled: ImportStreamResult = { root: parsed.root, config: parsed.config };
193
+ if (parsed.result !== undefined) {
194
+ settled.result = parsed.result;
195
+ }
196
+ return settled;
145
197
  } else if (parsed.type === "error") {
146
198
  throw new Error(parsed.error || "Import failed");
147
199
  }
148
200
  // Heartbeats and unknown line types are ignored.
201
+ return undefined;
149
202
  };
150
203
 
151
204
  try {
@@ -159,10 +212,10 @@ export async function streamImport(
159
212
  const lines = buffer.split("\n");
160
213
  buffer = lines.pop() ?? "";
161
214
  for (const line of lines) {
162
- handleLine(line);
215
+ result = handleLine(line) ?? result;
163
216
  }
164
217
  }
165
- handleLine(buffer);
218
+ result = handleLine(buffer) ?? result;
166
219
  } finally {
167
220
  try {
168
221
  await reader.cancel();
@@ -5,8 +5,8 @@
5
5
  * the turn and runs the import as a tool call. This holds what the form gathered for the one turn
6
6
  * that consumes it.
7
7
  *
8
- * **Module state, and deliberately NOT a copy of `agent-seed.ts`.** That one uses localStorage keyed
9
- * by project root because the project it seeds opens in a NEW WINDOW, and the key is the
8
+ * **Module state, and deliberately NOT a copy of `agent-seed.ts`.** That one uses localStorage
9
+ * keyed by project root because the project it seeds opens in a NEW WINDOW, and the key is the
10
10
  * cross-window channel. Neither half of that applies here: the project does not exist yet at
11
11
  * hand-off time, so there is no root to key on, and the assistant taking the turn is in this window
12
12
  * — `import_site` is `no-project` tiered precisely because it runs before there is a project. A
@@ -18,6 +18,12 @@
18
18
 
19
19
  import type { ImportBreakpointPolicy } from "../types";
20
20
 
21
+ /**
22
+ * The deepest crawl the import pipeline accepts: the bound `packages/server/src/import-api.ts`
23
+ * clamps to, which both the wizard's depth field and `import_site` honour.
24
+ */
25
+ export const MAX_IMPORT_DEPTH = 5;
26
+
21
27
  /** What the wizard gathered, as the tool needs it. */
22
28
  export interface ImportBrief {
23
29
  /** Absolute http(s) URL of the site to clone. */
@@ -19,21 +19,21 @@
19
19
 
20
20
  import coreDocumentSchema from "@jxsuite/schema/schema.json";
21
21
  import coreProjectSchema from "@jxsuite/schema/project-schema.json";
22
-
23
- type ValidateFn = ((doc: unknown) => boolean) & {
24
- errors?: { instancePath?: string; message?: string; params?: Record<string, unknown> }[] | null;
25
- };
22
+ import { isJsonObject, isString } from "@jxsuite/schema/guards";
23
+ import type { JsonObject, JsonValue, ProjectConfig } from "@jxsuite/schema/types";
24
+ import type { ValidateFunction } from "ajv/dist/2020.js";
25
+ import type { CandidateDocument } from "./ai-write-report";
26
26
 
27
27
  /** Which of the two entry documents a validator covers. */
28
28
  type SchemaKind = "document" | "project";
29
29
 
30
- const CORE: Record<SchemaKind, object> = {
31
- document: coreDocumentSchema as object,
32
- project: coreProjectSchema as object,
30
+ const CORE: Record<SchemaKind, JsonObject> = {
31
+ document: coreDocumentSchema,
32
+ project: coreProjectSchema,
33
33
  };
34
34
 
35
- const active: Record<SchemaKind, object> = { ...CORE };
36
- const compiling: Record<SchemaKind, Promise<ValidateFn | null> | null> = {
35
+ const active: Record<SchemaKind, JsonObject> = { ...CORE };
36
+ const compiling: Record<SchemaKind, Promise<ValidateFunction | null> | null> = {
37
37
  document: null,
38
38
  project: null,
39
39
  };
@@ -49,9 +49,9 @@ let reportedFailure = false;
49
49
  * unavailable or the schema will not compile.
50
50
  *
51
51
  * @param {SchemaKind} kind - Which entry document to compile
52
- * @returns {Promise<ValidateFn | null>} The compiled validator, or null when unavailable
52
+ * @returns {Promise<ValidateFunction | null>} The compiled validator, or null when unavailable
53
53
  */
54
- function getValidator(kind: SchemaKind): Promise<ValidateFn | null> {
54
+ function getValidator(kind: SchemaKind): Promise<ValidateFunction | null> {
55
55
  compiling[kind] ??= (async () => {
56
56
  try {
57
57
  // The generated schemas are JSON Schema draft 2020-12, so they need Ajv's 2020 build —
@@ -62,7 +62,7 @@ function getValidator(kind: SchemaKind): Promise<ValidateFn | null> {
62
62
  const { default: addFormats } = await import("ajv-formats");
63
63
  const ajv = new Ajv2020({ allErrors: true, strict: false, allowUnionTypes: true });
64
64
  addFormats(ajv);
65
- return ajv.compile(active[kind]) as ValidateFn;
65
+ return ajv.compile(active[kind]);
66
66
  } catch (error) {
67
67
  if (!reportedFailure) {
68
68
  reportedFailure = true;
@@ -78,14 +78,9 @@ function getValidator(kind: SchemaKind): Promise<ValidateFn | null> {
78
78
  return compiling[kind];
79
79
  }
80
80
 
81
- /** A payload half that is usable as a JSON Schema — a non-empty, non-array object. */
82
- function asSchema(value: unknown): object | undefined {
83
- return typeof value === "object" &&
84
- value !== null &&
85
- !Array.isArray(value) &&
86
- Object.keys(value).length > 0
87
- ? (value as object)
88
- : undefined;
81
+ /** Whether a payload half is usable as a JSON Schema — a non-empty, non-array object. */
82
+ function isSchemaObject(value: unknown): value is JsonObject {
83
+ return isJsonObject(value) && Object.keys(value).length > 0;
89
84
  }
90
85
 
91
86
  /**
@@ -107,8 +102,10 @@ export function applyProjectSchemas(
107
102
  * an error envelope under `document` would not fail loudly — it would install a validator that
108
103
  * calls every document valid, and every consumer would go on trusting it.
109
104
  */
110
- const document = asSchema(schemas?.document) ?? CORE.document;
111
- const project = asSchema(schemas?.project) ?? CORE.project;
105
+ const documentHalf = schemas?.document;
106
+ const projectHalf = schemas?.project;
107
+ const document = isSchemaObject(documentHalf) ? documentHalf : CORE.document;
108
+ const project = isSchemaObject(projectHalf) ? projectHalf : CORE.project;
112
109
  const applied = document !== CORE.document || project !== CORE.project;
113
110
  if (document === active.document && project === active.project) {
114
111
  return applied;
@@ -140,13 +137,13 @@ const ERROR_PROPERTY_KEYS = ["unevaluatedProperty", "additionalProperty", "missi
140
137
  * Format ajv errors the way the agent loop consumes them (see ai-tools.ts
141
138
  * `translateValidationError`).
142
139
  *
143
- * @param {ValidateFn} validate - The validator that just ran
140
+ * @param {ValidateFunction} validate - The validator that just ran
144
141
  * @returns {string[]} One formatted string per error
145
142
  */
146
- function formatErrors(validate: ValidateFn): string[] {
143
+ function formatErrors(validate: ValidateFunction): string[] {
147
144
  return (validate.errors || []).map((e) => {
148
- const key = ERROR_PROPERTY_KEYS.find((name) => typeof e.params?.[name] === "string");
149
- const property = key ? ` (${String(e.params?.[key])})` : "";
145
+ const key = ERROR_PROPERTY_KEYS.find((name) => isString(e.params[name]));
146
+ const property = key ? ` (${String(e.params[key])})` : "";
150
147
  return `${e.instancePath || "(root)"}: ${e.message}${property}`;
151
148
  });
152
149
  }
@@ -154,10 +151,10 @@ function formatErrors(validate: ValidateFn): string[] {
154
151
  /**
155
152
  * Validate a Jx document against the active document schema.
156
153
  *
157
- * @param {unknown} doc - Parsed document
154
+ * @param {CandidateDocument} doc - Parsed document
158
155
  * @returns {Promise<string[]>} Formatted error strings; empty when valid or validation unavailable
159
156
  */
160
- export async function validateDoc(doc: unknown): Promise<string[]> {
157
+ export async function validateDoc(doc: CandidateDocument): Promise<string[]> {
161
158
  const validate = await getValidator("document");
162
159
  if (!validate || validate(doc)) {
163
160
  return [];
@@ -176,7 +173,7 @@ export async function validateDoc(doc: unknown): Promise<string[]> {
176
173
  * @param doc - Parsed document
177
174
  * @returns The errors, `[]` when valid, or `null` when no validator could be compiled
178
175
  */
179
- export async function validateDocOrNull(doc: unknown): Promise<string[] | null> {
176
+ export async function validateDocOrNull(doc: CandidateDocument): Promise<string[] | null> {
180
177
  const validate = await getValidator("document");
181
178
  if (!validate) {
182
179
  return null;
@@ -190,10 +187,10 @@ export async function validateDocOrNull(doc: unknown): Promise<string[] | null>
190
187
  * extension's fragment), so this is the only gate that catches a typo'd section key or a misshapen
191
188
  * extension section before the write lands.
192
189
  *
193
- * @param {unknown} config - Parsed project.json
190
+ * @param {ProjectConfig | JsonValue} config - Parsed project.json
194
191
  * @returns {Promise<string[]>} Formatted error strings; empty when valid or validation unavailable
195
192
  */
196
- export async function validateProjectConfig(config: unknown): Promise<string[]> {
193
+ export async function validateProjectConfig(config: ProjectConfig | JsonValue): Promise<string[]> {
197
194
  const validate = await getValidator("project");
198
195
  if (!validate || validate(config)) {
199
196
  return [];
Binary file
@@ -173,12 +173,15 @@ export interface LiveSurfaceDeps {
173
173
  redefineOnCanvases: (doc: JxDocument, base: string) => number;
174
174
  }
175
175
 
176
- /** The sentence a result is said in. Exported so the wording is tested, not only the branch. */
177
- export function liveSaveNotice(result: LiveSurfaceResult): {
176
+ /** How a save's result is announced: the toast key it replaces, its level and its sentence. */
177
+ export interface LiveSaveNotice {
178
178
  key: string;
179
179
  level: "info" | "warn";
180
180
  message: string;
181
- } {
181
+ }
182
+
183
+ /** The sentence a result is said in. Exported so the wording is tested, not only the branch. */
184
+ export function liveSaveNotice(result: LiveSurfaceResult): LiveSaveNotice {
182
185
  const what =
183
186
  result.target.kind === "surface" ? `surface ${result.target.name}` : result.target.tag;
184
187
  const key = `live-chrome:${what}`;