@jxsuite/studio 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (613) hide show
  1. package/README.md +1 -1
  2. package/data/elements-meta.json +5 -15
  3. package/data/html-meta.json +51 -6
  4. package/dist/chunks/{2020-xp8vnwma.js → 2020-g79n01v9.js} +14 -14
  5. package/dist/chunks/action-group-sp6tna8v.js +118 -0
  6. package/dist/chunks/adapter-nj7tnjfn.js +13 -0
  7. package/dist/chunks/cf-account-picker-fyf63pmy.js +495 -0
  8. package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
  9. package/dist/chunks/color-area-v17df7b8.js +154 -0
  10. package/dist/chunks/color-field-anwybnkn.js +208 -0
  11. package/dist/chunks/color-slider-44ez96fc.js +79 -0
  12. package/dist/chunks/color-xgg3kfw7.js +35 -0
  13. package/dist/chunks/combobox-5e7jev23.js +236 -0
  14. package/dist/chunks/components-2w1f35qs.js +18 -0
  15. package/dist/chunks/content-source-3wqeas45.js +46 -0
  16. package/dist/chunks/convert-to-repeater-d0cgnb6d.js +639 -0
  17. package/dist/chunks/dialog-s890b918.js +85 -0
  18. package/dist/chunks/editor-3qhbg51x.js +35 -0
  19. package/dist/chunks/entry-commands-d6g50j7s.js +42 -0
  20. package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
  21. package/dist/chunks/file-ops-3btj6st0.js +47 -0
  22. package/dist/chunks/files-ef8fgs3w.js +72 -0
  23. package/dist/chunks/format-host-3c33nwr8.js +40 -0
  24. package/dist/chunks/fs-events-13tj6sex.js +18 -0
  25. package/dist/chunks/git-panel-4wp2rn9b.js +49 -0
  26. package/dist/chunks/icons-yy10wk9r.js +402 -0
  27. package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
  28. package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
  29. package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
  30. package/dist/chunks/iframe-host-jgesd924.js +115 -0
  31. package/dist/chunks/{index-nj44jpzj.js → index-mdmyx6s2.js} +11 -11
  32. package/dist/chunks/index-n4j7qxyr.js +109 -0
  33. package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
  34. package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
  35. package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
  36. package/dist/chunks/layers-1nq5evsh.js +29 -0
  37. package/dist/chunks/layers-panel-ar2gh90g.js +40 -0
  38. package/dist/chunks/listbox-6v2ac08j.js +44 -0
  39. package/dist/chunks/lit-html-m244w9nh.js +17 -0
  40. package/dist/chunks/media-picker-2qbetq73.js +33 -0
  41. package/dist/chunks/menu-q99sy9rf.js +285 -0
  42. package/dist/chunks/menu-rf7n72mf.js +14 -0
  43. package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
  44. package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
  45. package/dist/chunks/{monaco-setup-rws7k4br.js → monaco-setup-8r62fj6y.js} +27 -37
  46. package/dist/chunks/notify-628t0anh.js +21 -0
  47. package/dist/chunks/number-field-5cndyft8.js +72 -0
  48. package/dist/chunks/parse-0zx14y15.js +10 -0
  49. package/dist/chunks/platform-ts9cg1a4.js +15 -0
  50. package/dist/chunks/popover-47z3ytva.js +25 -0
  51. package/dist/chunks/publish-panel-98f7sr3g.js +27 -0
  52. package/dist/chunks/quick-search-srzz83k2.js +45 -0
  53. package/dist/chunks/references-n553f0e1.js +26 -0
  54. package/dist/chunks/right-panel-rrgx2dn3.js +45 -0
  55. package/dist/chunks/section-registry-5pq32t0q.js +25 -0
  56. package/dist/chunks/select-2r16ez41.js +49 -0
  57. package/dist/chunks/split-g7nm1rgb.js +191 -0
  58. package/dist/chunks/studio-0hqbpbd0.js +62 -0
  59. package/dist/chunks/studio-18avnhjp.js +2430 -0
  60. package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
  61. package/dist/chunks/{studio-hbtp0eh1.js → studio-25hkdrkw.js} +356 -85
  62. package/dist/chunks/studio-26d7myd1.js +258 -0
  63. package/dist/chunks/{studio-p8j86wag.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/studio-3gxv60tn.js +422 -0
  65. package/dist/chunks/{studio-8swrjbny.js → studio-3hxkd92t.js} +275 -163
  66. package/dist/chunks/studio-4m0haseg.js +185 -0
  67. package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
  68. package/dist/chunks/{studio-gv8vvshc.js → studio-5523bpzt.js} +11 -11
  69. package/dist/chunks/{studio-5q69gfag.js → studio-57mf66w2.js} +1753 -2484
  70. package/dist/chunks/studio-5jy81t3s.js +17463 -0
  71. package/dist/chunks/studio-5rt7sqa0.js +1168 -0
  72. package/dist/chunks/studio-5te5tqng.js +81 -0
  73. package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
  74. package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
  75. package/dist/chunks/studio-6xa21ej9.js +28 -0
  76. package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
  77. package/dist/chunks/{studio-eenfkt4e.js → studio-79y5sz51.js} +52 -38
  78. package/dist/chunks/{studio-4q0wznzf.js → studio-7e11jpa9.js} +461 -145
  79. package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
  80. package/dist/chunks/studio-7xptrg0j.js +954 -0
  81. package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
  82. package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
  83. package/dist/chunks/studio-8qtrpzr3.js +839 -0
  84. package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
  85. package/dist/chunks/studio-9xxz1q69.js +1356 -0
  86. package/dist/chunks/studio-akbww0j5.js +13615 -0
  87. package/dist/chunks/studio-arfpe389.js +195 -0
  88. package/dist/chunks/{studio-2zkz8evn.js → studio-az3zd49t.js} +473 -281
  89. package/dist/chunks/studio-cpvb2ed1.js +1171 -0
  90. package/dist/chunks/{studio-9r6j5ev1.js → studio-d0300636.js} +5078 -19
  91. package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
  92. package/dist/chunks/studio-d1ja2x9r.js +362 -0
  93. package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
  94. package/dist/chunks/{studio-4pqqxbrt.js → studio-em9nw8eh.js} +301 -112
  95. package/dist/chunks/studio-erdatzvp.js +1190 -0
  96. package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
  97. package/dist/chunks/studio-fabxk6r9.js +2811 -0
  98. package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
  99. package/dist/chunks/studio-hhvs4sdg.js +195 -0
  100. package/dist/chunks/{studio-68n67094.js → studio-kcgff4r0.js} +15 -18
  101. package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
  102. package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
  103. package/dist/chunks/studio-pm6hgy7r.js +4763 -0
  104. package/dist/chunks/studio-q0a3yk4n.js +33 -0
  105. package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
  106. package/dist/chunks/studio-qahxvnan.js +111 -0
  107. package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
  108. package/dist/chunks/{studio-kjjsjak4.js → studio-rkstz940.js} +3661 -6136
  109. package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
  110. package/dist/chunks/studio-rpyah2ew.js +2805 -0
  111. package/dist/chunks/studio-rs76k67r.js +12 -0
  112. package/dist/chunks/{studio-yxrkyv8a.js → studio-s6z853aq.js} +12108 -11766
  113. package/dist/chunks/{studio-sf7zjgv1.js → studio-sgdc5pfc.js} +8 -8
  114. package/dist/chunks/studio-tb3ev01j.js +763 -0
  115. package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
  116. package/dist/chunks/studio-vhv5tgxm.js +51 -0
  117. package/dist/chunks/{studio-htsf0w6m.js → studio-vz68yn9e.js} +31 -154
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/{studio-eesa1myv.js → studio-x3rty6tr.js} +58 -58
  120. package/dist/chunks/studio-xsykpvsh.js +8448 -0
  121. package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
  122. package/dist/chunks/studio-yxa81f45.js +12 -0
  123. package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
  124. package/dist/chunks/tabs-wbp1cdws.js +156 -0
  125. package/dist/chunks/textfield-abk6qyee.js +73 -0
  126. package/dist/chunks/toast-780pvfbv.js +27 -0
  127. package/dist/chunks/toast-host-3sqv46sn.js +116 -0
  128. package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
  129. package/dist/chunks/tooltip-eptb614w.js +369 -0
  130. package/dist/chunks/tree-a73p0pqm.js +367 -0
  131. package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
  132. package/dist/chunks/workspace-wrew8zk4.js +69 -0
  133. package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
  134. package/dist/iframe-entry.js +1812 -698
  135. package/dist/manifest.json +7 -0
  136. package/dist/studio.js +52900 -36573
  137. package/dist/workers/editor.worker.js +1040 -1085
  138. package/dist/workers/json.worker.js +1946 -1991
  139. package/dist/workers/ts.worker.js +4960 -5005
  140. package/favicon.ico +0 -0
  141. package/index.html +2 -0
  142. package/package.json +22 -55
  143. package/src/about/about-modal.ts +73 -123
  144. package/src/browse/library-commands.ts +20 -49
  145. package/src/browse/library-layouts.ts +87 -218
  146. package/src/browse/library-pane.ts +406 -438
  147. package/src/canvas/canvas-helpers.ts +0 -49
  148. package/src/canvas/canvas-live-render.ts +25 -2
  149. package/src/canvas/canvas-render.ts +666 -231
  150. package/src/canvas/canvas-surface.ts +0 -1
  151. package/src/canvas/canvas-utils.ts +310 -117
  152. package/src/canvas/dialog-path.ts +76 -0
  153. package/src/canvas/dialog-state.ts +67 -0
  154. package/src/canvas/diff-marks.ts +252 -0
  155. package/src/canvas/diff-toolbar.ts +349 -0
  156. package/src/canvas/diff-view.ts +123 -0
  157. package/src/canvas/edit-width-drag.ts +187 -0
  158. package/src/canvas/edit-width.ts +150 -0
  159. package/src/canvas/iframe-entry.ts +125 -8
  160. package/src/canvas/iframe-host.ts +271 -15
  161. package/src/canvas/iframe-interaction.ts +133 -13
  162. package/src/canvas/iframe-patch.ts +7 -1
  163. package/src/canvas/iframe-position.ts +5 -6
  164. package/src/canvas/iframe-protocol.ts +106 -5
  165. package/src/canvas/iframe-render.ts +373 -5
  166. package/src/canvas/iframe-slash.ts +2 -2
  167. package/src/canvas/iframe-subtree.ts +5 -8
  168. package/src/canvas/path-mapping.ts +25 -3
  169. package/src/canvas/popover-path.ts +106 -0
  170. package/src/canvas/popover-state.ts +155 -0
  171. package/src/canvas/surface-registry.ts +21 -10
  172. package/src/collab/presence-chips.ts +51 -73
  173. package/src/commands/app-commands.ts +10 -0
  174. package/src/commands/budget.ts +12 -0
  175. package/src/commands/command-args.ts +369 -6
  176. package/src/commands/defaults.ts +44 -14
  177. package/src/commands/live-context.ts +11 -5
  178. package/src/commands/reference.ts +12 -2
  179. package/src/commands/registry.ts +165 -8
  180. package/src/content/entry-commands.ts +16 -23
  181. package/src/content/entry-editor.ts +144 -101
  182. package/src/editor/canvas-slash-bridge.ts +2 -2
  183. package/src/editor/context-menu.ts +49 -200
  184. package/src/editor/convert-to-component.ts +42 -82
  185. package/src/editor/convert-to-repeater.ts +132 -173
  186. package/src/editor/inline-edit.ts +11 -0
  187. package/src/editor/shortcuts.ts +65 -26
  188. package/src/editor/slash-menu.ts +150 -157
  189. package/src/files/file-ops.ts +117 -11
  190. package/src/files/files.ts +949 -664
  191. package/src/files/json-layout.ts +474 -0
  192. package/src/files/media-paths.ts +13 -42
  193. package/src/files/media-usage.ts +41 -131
  194. package/src/files/serialize-document.ts +8 -1
  195. package/src/format/convert-file.ts +16 -10
  196. package/src/format/format-host.ts +50 -1
  197. package/src/github/github-auth.ts +71 -29
  198. package/src/github/github-publish.ts +57 -65
  199. package/src/grid/cell-editors.ts +46 -4
  200. package/src/grid/cell-popovers.ts +65 -62
  201. package/src/grid/grid-open.ts +86 -64
  202. package/src/grid/grid-panel.ts +390 -469
  203. package/src/grid/redirects-grid.ts +40 -44
  204. package/src/hosting/document.ts +2 -0
  205. package/src/hosting/layout.ts +10 -0
  206. package/src/i18n/i18n-commands.ts +127 -62
  207. package/src/media/media-pane.ts +83 -133
  208. package/src/new-project/add-repo-modal.ts +125 -176
  209. package/src/new-project/import-tab.ts +201 -250
  210. package/src/new-project/location-fields.ts +101 -165
  211. package/src/new-project/new-project-modal.ts +376 -367
  212. package/src/packages/jxsuite-update.ts +76 -18
  213. package/src/panels/activity-panel.ts +137 -104
  214. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  215. package/src/panels/ai-chat/chat-view.ts +307 -472
  216. package/src/panels/ai-chat/composer.ts +175 -153
  217. package/src/panels/ai-chat/sessions-view.ts +31 -62
  218. package/src/panels/ai-panel.ts +210 -185
  219. package/src/panels/block-action-bar.ts +437 -643
  220. package/src/panels/bottom-dock.ts +112 -47
  221. package/src/panels/chat-panel.ts +19 -14
  222. package/src/panels/data-explorer.ts +141 -102
  223. package/src/panels/data-grid.ts +183 -150
  224. package/src/panels/dnd.ts +75 -20
  225. package/src/panels/editors.ts +26 -19
  226. package/src/panels/elements-panel.ts +243 -186
  227. package/src/panels/empty-state.ts +26 -42
  228. package/src/panels/events-panel.ts +950 -729
  229. package/src/panels/formula-workspace.ts +434 -207
  230. package/src/panels/frontmatter-fields.ts +185 -153
  231. package/src/panels/frontmatter-panel.ts +411 -187
  232. package/src/panels/git-diff-open.ts +148 -0
  233. package/src/panels/git-panel.ts +679 -605
  234. package/src/panels/head-panel.ts +617 -435
  235. package/src/panels/i18n-panel.ts +153 -133
  236. package/src/panels/imports-panel.ts +388 -414
  237. package/src/panels/jump-bar.ts +174 -147
  238. package/src/panels/layers-panel.ts +785 -671
  239. package/src/panels/left-panel.ts +166 -94
  240. package/src/panels/navigator-panels.ts +1 -1
  241. package/src/panels/pane-context.ts +529 -677
  242. package/src/panels/pane-grid.ts +265 -241
  243. package/src/panels/panel-registry.ts +15 -4
  244. package/src/panels/problems-panel.ts +177 -99
  245. package/src/panels/properties-panel.ts +1525 -966
  246. package/src/panels/provenance.ts +31 -113
  247. package/src/panels/quick-search.ts +217 -172
  248. package/src/panels/right-panel.ts +135 -169
  249. package/src/panels/seo-modal.ts +346 -167
  250. package/src/panels/settings-menu.ts +109 -646
  251. package/src/panels/settings-pane.ts +102 -86
  252. package/src/panels/signals-panel.ts +1318 -1172
  253. package/src/panels/statement-editor.ts +556 -428
  254. package/src/panels/style-panel.ts +1367 -630
  255. package/src/panels/style-utils.ts +36 -32
  256. package/src/panels/stylebook-doc.ts +30 -73
  257. package/src/panels/stylebook-layers-panel.ts +202 -109
  258. package/src/panels/stylebook-panel.ts +124 -88
  259. package/src/panels/tab-strip.ts +385 -287
  260. package/src/platforms/cloud.ts +347 -86
  261. package/src/platforms/devserver.ts +13 -0
  262. package/src/publish/deploy-checklist.ts +124 -78
  263. package/src/publish/publish-commands.ts +4 -12
  264. package/src/publish/publish-panel.ts +165 -299
  265. package/src/services/a11y-report.ts +100 -43
  266. package/src/services/ai-command-tools.ts +468 -0
  267. package/src/services/ai-import-tools.ts +50 -12
  268. package/src/services/ai-models.ts +108 -1
  269. package/src/services/ai-session-store.ts +6 -0
  270. package/src/services/ai-system-prompt.ts +110 -18
  271. package/src/services/ai-tools.ts +28 -143
  272. package/src/services/ai-write-report.ts +174 -0
  273. package/src/services/context-manager.ts +12 -1
  274. package/src/services/document-assistant.ts +50 -2
  275. package/src/services/idle.ts +16 -14
  276. package/src/services/live-surfaces.ts +237 -0
  277. package/src/services/model-uri.ts +75 -0
  278. package/src/services/notify.ts +63 -6
  279. package/src/services/popover-report.ts +325 -0
  280. package/src/services/surface-registry.ts +56 -0
  281. package/src/services/tool-executor.ts +17 -0
  282. package/src/settings/contexts-section.ts +301 -299
  283. package/src/settings/contributed-section.ts +361 -222
  284. package/src/settings/css-vars-editor.ts +320 -325
  285. package/src/settings/defs-editor.ts +572 -535
  286. package/src/settings/dependencies-editor.ts +79 -107
  287. package/src/settings/extension-commands.ts +379 -0
  288. package/src/settings/extension-rows.ts +113 -0
  289. package/src/settings/extensions-section.ts +287 -0
  290. package/src/settings/general-settings.ts +130 -181
  291. package/src/settings/head-editor.ts +10 -305
  292. package/src/settings/locales-section.ts +146 -196
  293. package/src/settings/preferences-accounts.ts +193 -12
  294. package/src/settings/preferences-dialog.ts +384 -307
  295. package/src/settings/project-sections.ts +108 -181
  296. package/src/settings/schema-field-ui.ts +11 -399
  297. package/src/settings/section-registry.ts +8 -1
  298. package/src/settings/settings-document.ts +31 -29
  299. package/src/shell/tree.ts +42 -87
  300. package/src/shell.ts +48 -36
  301. package/src/studio.ts +90 -67
  302. package/src/style/token-ref.ts +0 -39
  303. package/src/surfaces/about.json +263 -0
  304. package/src/surfaces/about.ts +163 -0
  305. package/src/surfaces/add-repo.json +486 -0
  306. package/src/surfaces/add-repo.ts +236 -0
  307. package/src/surfaces/ai-chat.json +2185 -0
  308. package/src/surfaces/ai-chat.ts +549 -0
  309. package/src/surfaces/ai-credentials-form.json +332 -0
  310. package/src/surfaces/ai-credentials-form.ts +151 -0
  311. package/src/surfaces/ai-managed-connect.json +108 -0
  312. package/src/surfaces/ai-managed-connect.ts +123 -0
  313. package/src/surfaces/ai-model-picker.json +114 -0
  314. package/src/surfaces/ai-model-picker.ts +139 -0
  315. package/src/surfaces/block-action-bar.json +640 -0
  316. package/src/surfaces/block-action-bar.ts +368 -0
  317. package/src/surfaces/bottom-dock.json +154 -0
  318. package/src/surfaces/bottom-dock.ts +125 -0
  319. package/src/surfaces/canvas-stage.json +444 -0
  320. package/src/surfaces/canvas-stage.ts +253 -0
  321. package/src/surfaces/cf-account-picker.json +300 -0
  322. package/src/surfaces/cf-account-picker.ts +214 -0
  323. package/src/surfaces/commandbar.json +984 -0
  324. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
  325. package/src/surfaces/convert-repeater.json +309 -0
  326. package/src/surfaces/convert-repeater.ts +276 -0
  327. package/src/surfaces/data-actions.json +157 -0
  328. package/src/surfaces/data-actions.ts +115 -0
  329. package/src/surfaces/dialog.json +289 -0
  330. package/src/surfaces/dialog.ts +343 -0
  331. package/src/surfaces/diff-toolbar.json +266 -0
  332. package/src/surfaces/diff-toolbar.ts +139 -0
  333. package/src/surfaces/doc-header.json +739 -0
  334. package/src/surfaces/doc-header.ts +223 -0
  335. package/src/surfaces/empty-state.json +152 -0
  336. package/src/surfaces/empty-state.ts +173 -0
  337. package/src/surfaces/entry-editor.json +281 -0
  338. package/src/surfaces/entry-editor.ts +191 -0
  339. package/src/surfaces/expression-editor.json +977 -0
  340. package/src/surfaces/expression-editor.ts +266 -0
  341. package/src/surfaces/files-panel.json +592 -0
  342. package/src/surfaces/files-panel.ts +301 -0
  343. package/src/surfaces/formula-palette.json +364 -0
  344. package/src/surfaces/formula-palette.ts +340 -0
  345. package/src/surfaces/git-panel.json +1822 -0
  346. package/src/surfaces/git-panel.ts +272 -0
  347. package/src/surfaces/github-auth.json +112 -0
  348. package/src/surfaces/github-auth.ts +139 -0
  349. package/src/surfaces/github-publish.json +206 -0
  350. package/src/surfaces/github-publish.ts +169 -0
  351. package/src/surfaces/grid-cell.json +218 -0
  352. package/src/surfaces/grid-cell.ts +120 -0
  353. package/src/surfaces/grid-open.json +147 -0
  354. package/src/surfaces/grid-open.ts +87 -0
  355. package/src/surfaces/grid-panel.json +706 -0
  356. package/src/surfaces/grid-panel.ts +206 -0
  357. package/src/surfaces/grid-replace.json +179 -0
  358. package/src/surfaces/grid-replace.ts +89 -0
  359. package/src/surfaces/grid-views.json +446 -0
  360. package/src/surfaces/grid-views.ts +172 -0
  361. package/src/surfaces/inspector-dock.json +187 -0
  362. package/src/surfaces/inspector-dock.ts +161 -0
  363. package/src/surfaces/jump-bar.json +243 -0
  364. package/src/surfaces/jump-bar.ts +129 -0
  365. package/src/surfaces/jxsuite-update.json +146 -0
  366. package/src/surfaces/jxsuite-update.ts +149 -0
  367. package/src/surfaces/library-pane.json +1509 -0
  368. package/src/surfaces/library-pane.ts +363 -0
  369. package/src/surfaces/logic-panel.json +1949 -0
  370. package/src/surfaces/logic-panel.ts +369 -0
  371. package/src/surfaces/logic-workspace.json +685 -0
  372. package/src/surfaces/logic-workspace.ts +238 -0
  373. package/src/surfaces/media-browser.json +303 -0
  374. package/src/surfaces/media-browser.ts +145 -0
  375. package/src/surfaces/media-field.json +163 -0
  376. package/src/surfaces/media-field.ts +116 -0
  377. package/src/surfaces/media-pane.json +513 -0
  378. package/src/surfaces/media-pane.ts +197 -0
  379. package/src/surfaces/menu.json +232 -0
  380. package/src/surfaces/menu.ts +375 -0
  381. package/src/surfaces/navigator-dock.json +113 -0
  382. package/src/surfaces/navigator-dock.ts +130 -0
  383. package/src/surfaces/new-project.json +1654 -0
  384. package/src/surfaces/new-project.ts +411 -0
  385. package/src/surfaces/palette.json +535 -0
  386. package/src/surfaces/pane-context.json +1497 -0
  387. package/src/surfaces/pane-context.ts +513 -0
  388. package/src/surfaces/pane-grid.json +188 -0
  389. package/src/surfaces/pane-grid.ts +250 -0
  390. package/src/surfaces/panel-activity.json +563 -0
  391. package/src/surfaces/panel-activity.ts +187 -0
  392. package/src/surfaces/panel-data.json +141 -0
  393. package/src/surfaces/panel-data.ts +156 -0
  394. package/src/surfaces/panel-deploy-checklist.json +283 -0
  395. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  396. package/src/surfaces/panel-elements.json +367 -0
  397. package/src/surfaces/panel-elements.ts +175 -0
  398. package/src/surfaces/panel-i18n.json +569 -0
  399. package/src/surfaces/panel-i18n.ts +212 -0
  400. package/src/surfaces/panel-imports.json +780 -0
  401. package/src/surfaces/panel-imports.ts +209 -0
  402. package/src/surfaces/panel-outline.json +734 -0
  403. package/src/surfaces/panel-outline.ts +326 -0
  404. package/src/surfaces/panel-page.json +1017 -0
  405. package/src/surfaces/panel-page.ts +240 -0
  406. package/src/surfaces/panel-problems.json +497 -0
  407. package/src/surfaces/panel-problems.ts +157 -0
  408. package/src/surfaces/panel-signals.json +1973 -0
  409. package/src/surfaces/panel-signals.ts +436 -0
  410. package/src/surfaces/panel-stylebook-layers.json +317 -0
  411. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  412. package/src/surfaces/preferences.json +850 -0
  413. package/src/surfaces/preferences.ts +332 -0
  414. package/src/surfaces/progress-modal.json +110 -0
  415. package/src/surfaces/progress-modal.ts +150 -0
  416. package/src/surfaces/properties-panel.json +1578 -0
  417. package/src/surfaces/properties-panel.ts +337 -0
  418. package/src/surfaces/publish.json +945 -0
  419. package/src/surfaces/publish.ts +392 -0
  420. package/src/surfaces/push-plan.json +110 -0
  421. package/src/surfaces/push-plan.ts +87 -0
  422. package/src/surfaces/rail.json +255 -0
  423. package/src/surfaces/rail.ts +206 -0
  424. package/src/surfaces/reference-field.json +191 -0
  425. package/src/surfaces/reference-field.ts +168 -0
  426. package/src/surfaces/schema-builder.json +1011 -0
  427. package/src/surfaces/schema-builder.ts +181 -0
  428. package/src/surfaces/schema-form.json +1013 -0
  429. package/src/surfaces/schema-form.ts +287 -0
  430. package/src/surfaces/secret-field.json +60 -0
  431. package/src/surfaces/secret-field.ts +146 -0
  432. package/src/surfaces/seo.json +932 -0
  433. package/src/surfaces/seo.ts +334 -0
  434. package/src/surfaces/settings-contexts.json +538 -0
  435. package/src/surfaces/settings-contexts.ts +196 -0
  436. package/src/surfaces/settings-contributed.json +489 -0
  437. package/src/surfaces/settings-contributed.ts +199 -0
  438. package/src/surfaces/settings-css-vars.json +820 -0
  439. package/src/surfaces/settings-css-vars.ts +199 -0
  440. package/src/surfaces/settings-defs.json +1363 -0
  441. package/src/surfaces/settings-defs.ts +232 -0
  442. package/src/surfaces/settings-deploy.json +108 -0
  443. package/src/surfaces/settings-deploy.ts +135 -0
  444. package/src/surfaces/settings-extensions.json +486 -0
  445. package/src/surfaces/settings-extensions.ts +201 -0
  446. package/src/surfaces/settings-head.json +779 -0
  447. package/src/surfaces/settings-head.ts +397 -0
  448. package/src/surfaces/settings-locales.json +420 -0
  449. package/src/surfaces/settings-locales.ts +137 -0
  450. package/src/surfaces/settings-overview.json +423 -0
  451. package/src/surfaces/settings-overview.ts +218 -0
  452. package/src/surfaces/settings-packages.json +549 -0
  453. package/src/surfaces/settings-packages.ts +158 -0
  454. package/src/surfaces/settings-pane.json +147 -0
  455. package/src/surfaces/settings-pane.ts +150 -0
  456. package/src/surfaces/settings-rawjson.json +104 -0
  457. package/src/surfaces/settings-rawjson.ts +107 -0
  458. package/src/surfaces/shell.json +99 -0
  459. package/src/surfaces/shell.ts +30 -0
  460. package/src/surfaces/slash-menu.json +180 -0
  461. package/src/surfaces/slash-menu.ts +272 -0
  462. package/src/surfaces/statements.json +607 -0
  463. package/src/surfaces/statements.ts +238 -0
  464. package/src/surfaces/statusbar.json +94 -0
  465. package/src/{panels → surfaces}/statusbar.ts +163 -90
  466. package/src/surfaces/style-panel.json +1643 -0
  467. package/src/surfaces/style-panel.ts +338 -0
  468. package/src/surfaces/stylebook-chrome.json +122 -0
  469. package/src/surfaces/stylebook-chrome.ts +122 -0
  470. package/src/surfaces/tab-strip.json +448 -0
  471. package/src/surfaces/tab-strip.ts +200 -0
  472. package/src/surfaces/target-line.json +419 -0
  473. package/src/surfaces/target-line.ts +349 -0
  474. package/src/surfaces/toasts.json +189 -0
  475. package/src/surfaces/welcome.json +571 -0
  476. package/src/surfaces/welcome.ts +338 -0
  477. package/src/tabs/project-config.ts +71 -15
  478. package/src/tabs/tab.ts +52 -1
  479. package/src/types.ts +49 -3
  480. package/src/ui/ai-credentials-form.ts +104 -100
  481. package/src/ui/ai-managed-connect.ts +116 -49
  482. package/src/ui/ai-model-picker.ts +102 -47
  483. package/src/ui/cf-account-picker.ts +135 -0
  484. package/src/ui/color-selector.ts +80 -301
  485. package/src/ui/dynamic-slot.ts +43 -283
  486. package/src/ui/expression-editor.ts +797 -576
  487. package/src/ui/field-input.ts +8 -181
  488. package/src/ui/form-controls.ts +838 -366
  489. package/src/ui/formula-chips.ts +80 -85
  490. package/src/ui/kit.ts +33 -0
  491. package/src/ui/layers.ts +293 -593
  492. package/src/ui/media-picker.ts +203 -284
  493. package/src/ui/panel-resize.ts +251 -64
  494. package/src/ui/popover-surface.ts +153 -0
  495. package/src/ui/progress-modal.ts +22 -60
  496. package/src/ui/regions.ts +13 -7
  497. package/src/ui/schema-form.ts +906 -440
  498. package/src/ui/surface.ts +122 -0
  499. package/src/ui/unit-selector.ts +15 -131
  500. package/src/ui/value-source.ts +14 -0
  501. package/src/ui/virtual-window.ts +88 -9
  502. package/src/utils/canvas-media.ts +72 -0
  503. package/src/utils/edit-display.ts +7 -2
  504. package/src/utils/element-selectors.ts +69 -0
  505. package/src/utils/link-target.ts +2 -2
  506. package/src/utils/studio-utils.ts +0 -10
  507. package/src/view.ts +15 -0
  508. package/src/workspace/pane-derive.ts +36 -14
  509. package/src/workspace/workspace.ts +15 -6
  510. package/styles/canvas.css +72 -467
  511. package/styles/forced-colors.css +48 -82
  512. package/styles/forced-colors.json +41 -0
  513. package/styles/inspector.css +2 -1301
  514. package/styles/overlays.css +96 -2823
  515. package/styles/panels.css +6 -1423
  516. package/styles/shell-frame.css +272 -0
  517. package/styles/shell-frame.json +227 -0
  518. package/styles/shell.css +0 -1532
  519. package/styles/tokens.css +65 -136
  520. package/styles/tokens.json +84 -0
  521. package/dist/chunks/Overlay.dev-723bv0df.js +0 -23
  522. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  523. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  524. package/dist/chunks/components-zmx10t62.js +0 -21
  525. package/dist/chunks/content-source-t88vb2dr.js +0 -49
  526. package/dist/chunks/convert-to-repeater-dhw1nrz9.js +0 -268
  527. package/dist/chunks/editor-cptq5jp1.js +0 -37
  528. package/dist/chunks/entry-commands-6z6bhxg0.js +0 -46
  529. package/dist/chunks/extension-sections-3ydgjbdy.js +0 -311
  530. package/dist/chunks/file-ops-rskmhxyq.js +0 -48
  531. package/dist/chunks/files-0cratsr0.js +0 -92
  532. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  533. package/dist/chunks/focus-trap.esm-ggawf1hy.js +0 -1024
  534. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  535. package/dist/chunks/format-host-tgcmfs4p.js +0 -43
  536. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  537. package/dist/chunks/git-panel-0yywyk76.js +0 -58
  538. package/dist/chunks/index-zqxmqxmh.js +0 -109
  539. package/dist/chunks/jx-validate-8q2g05x1.js +0 -19
  540. package/dist/chunks/layers-panel-z3tqe5cd.js +0 -67
  541. package/dist/chunks/layers-q75tj2mf.js +0 -45
  542. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  543. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  544. package/dist/chunks/notify-yjm79n4s.js +0 -30
  545. package/dist/chunks/parse-24d0gay3.js +0 -19
  546. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  547. package/dist/chunks/publish-panel-54jvhskq.js +0 -28
  548. package/dist/chunks/quick-search-cgfmjwq5.js +0 -65
  549. package/dist/chunks/references-3qx8fkyp.js +0 -29
  550. package/dist/chunks/right-panel-cqp8bc4v.js +0 -46
  551. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  552. package/dist/chunks/sp-overlay.dev-yztmtrs1.js +0 -18
  553. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  554. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  555. package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +0 -15
  556. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  557. package/dist/chunks/studio-0a5qrh01.js +0 -3
  558. package/dist/chunks/studio-18j3bmcz.js +0 -14
  559. package/dist/chunks/studio-1hbqnt19.js +0 -1823
  560. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  561. package/dist/chunks/studio-5rywrkxz.js +0 -1903
  562. package/dist/chunks/studio-7afd21nw.js +0 -67
  563. package/dist/chunks/studio-7nte2hj4.js +0 -613
  564. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  565. package/dist/chunks/studio-8q517dfr.js +0 -24
  566. package/dist/chunks/studio-9c4k4vhv.js +0 -357
  567. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  568. package/dist/chunks/studio-a0tswy0w.js +0 -58
  569. package/dist/chunks/studio-ahjfdy6e.js +0 -387
  570. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  571. package/dist/chunks/studio-bw5dz6km.js +0 -608
  572. package/dist/chunks/studio-cb12yz9w.js +0 -15055
  573. package/dist/chunks/studio-d1ks410h.js +0 -175
  574. package/dist/chunks/studio-eqq1w638.js +0 -113
  575. package/dist/chunks/studio-ex8zyp98.js +0 -1813
  576. package/dist/chunks/studio-h4rxscfc.js +0 -10
  577. package/dist/chunks/studio-kyh9avvv.js +0 -28
  578. package/dist/chunks/studio-kyk2v92a.js +0 -659
  579. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  580. package/dist/chunks/studio-mmv72a27.js +0 -4344
  581. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  582. package/dist/chunks/studio-pdfjntbk.js +0 -6939
  583. package/dist/chunks/studio-qq6jym04.js +0 -53
  584. package/dist/chunks/studio-r1r7afxx.js +0 -1066
  585. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  586. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  587. package/dist/chunks/studio-t7qb9db8.js +0 -665
  588. package/dist/chunks/studio-tmc5emrw.js +0 -8
  589. package/dist/chunks/studio-txwkm6p9.js +0 -12
  590. package/dist/chunks/studio-v38hmvx1.js +0 -390
  591. package/dist/chunks/studio-vadzgkrz.js +0 -318
  592. package/dist/chunks/studio-wx5609xd.js +0 -341
  593. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  594. package/dist/chunks/studio-zczps70q.js +0 -378
  595. package/dist/chunks/workspace-xpres40v.js +0 -89
  596. package/src/panels/activity-bar.ts +0 -251
  597. package/src/panels/panel-scheduler.ts +0 -219
  598. package/src/panels/style-inputs.ts +0 -237
  599. package/src/panels/target-line.ts +0 -274
  600. package/src/panels/welcome-screen.ts +0 -346
  601. package/src/ui/button-group.ts +0 -102
  602. package/src/ui/choice-field.ts +0 -72
  603. package/src/ui/field-row.ts +0 -249
  604. package/src/ui/formula-palette.ts +0 -213
  605. package/src/ui/icons.ts +0 -52
  606. package/src/ui/jx-theme.ts +0 -130
  607. package/src/ui/spectrum.ts +0 -340
  608. package/src/ui/value-selector.ts +0 -174
  609. package/src/ui/widgets.ts +0 -172
  610. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  611. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  612. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  613. /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
@@ -1,164 +1,74 @@
1
1
  /**
2
- * Media usage — "which pages use this image?", asked in the shape an author actually wrote.
2
+ * Media usage — "which pages use this image?", asked once.
3
3
  *
4
- * `services/references.ts` already answers "where is this used?" for documents, and its answer is
5
- * what every destructive confirmation says out loud. Media does not fit through it unmodified, for
6
- * one reason: **the reference index resolves refs, and a media file's authored ref usually resolves
7
- * somewhere else.** `public/hero.jpg` is written `/hero.jpg`, which the compiler — and therefore
8
- * the sweep — resolves to `hero.jpg`. Ask about the file and every reference to it is invisible;
9
- * the query succeeds, returns zero, and the delete dialog says nothing else refers to it while
10
- * seven pages break. A confident zero is the one answer a destructive dialog must never invent.
4
+ * `services/references.ts` answers "where is this used?" for every kind of file, and its answer is
5
+ * what every destructive confirmation says out loud. Media needs three things on top of it, and no
6
+ * longer needs the fourth this module was built for.
11
7
  *
12
- * So the query is keyed on the AUTHORED ref. {@link authoredRefTargets} enumerates every path a
13
- * reference to this file resolves to — the file, its served path, its asset-mount path — and this
14
- * module asks all of them and unions the answers. Everything else is deliberately inherited rather
15
- * than re-implemented: the same `loadUsages` cache (so a dialog and a panel asking at once are one
16
- * round trip), the same `invalidateUsages` on any filesystem event, the same `usageWarning`
17
- * sentence in the confirmation, and the same `usageHeadline` wording on a panel.
8
+ * **What it still does.** A media path is normalized before it becomes a query (a leading `./` is
9
+ * not part of a file's identity), an empty path is a FAILURE rather than "nothing uses it", and
10
+ * {@link mediaUsageHeadline} renders the one line a media surface shows beside a file — where a
11
+ * failed query says **unknown**, which is a different fact from "unused" and has to read like one.
18
12
  *
19
- * **A partial answer is `failed`, not a total.** If one lane of the union cannot be counted, the
20
- * union cannot either — a number assembled from the lanes that worked reads exactly like a complete
21
- * one, and would understate what a delete breaks. Unknown is the honest answer, and
22
- * {@link mediaUsageHeadline} says the word.
13
+ * **What it no longer does, and why that matters.** A media file's authored reference usually
14
+ * resolves somewhere else: `public/hero.jpg` is written `/hero.jpg`, and a content asset is written
15
+ * `./images/hero.png` and republished at its collection's mount. `findReferences` used to resolve a
16
+ * rooted reference against the project root ALONE, so asking it about the file matched none of
17
+ * those and returned a confident zero — the one answer a destructive dialog must never invent. This
18
+ * module's answer was to enumerate every authored spelling of the file and union the results.
19
+ *
20
+ * That was a workaround in the wrong place. A client-side union can make a COUNT come out right and
21
+ * can do nothing at all about the REWRITE, which happens inside the engine — so the engine learned
22
+ * to resolve every lane itself (issue 239/241, `site-architecture.md` §9.3), and the union became a
23
+ * second implementation of a rule that now has one. It is gone: one path in, one query, one answer,
24
+ * and the lanes are the engine's business.
23
25
  *
24
26
  * @docs studio/projects/media
25
27
  */
26
28
 
27
- import { authoredRefTargets } from "./media-paths";
29
+ import { normalizeProjectPath } from "./media-paths";
28
30
  import { loadUsages, peekUsages, retryUsages, usageHeadline } from "../services/references";
29
- import type { UsageQuery, UsageState } from "../services/references";
30
- import type { ReferenceFile, ReferenceHit, ReferencesResult } from "../types";
31
+ import type { UsageState } from "../services/references";
31
32
 
32
- /**
33
- * The queries whose union answers "what uses this media file?".
34
- *
35
- * One per authored form. An empty list means there is no question to ask (an empty path), which
36
- * {@link loadMediaUsages} reports as a failure rather than as "nothing uses it".
37
- */
38
- export function mediaUsageQueries(path: string): UsageQuery[] {
39
- return authoredRefTargets(path).map((target) => ({ path: target }));
40
- }
41
-
42
- /** Merge one file's hits into the accumulator, summing counts per `(refType, ref)`. */
43
- function mergeFile(into: Map<string, ReferenceFile>, file: ReferenceFile): void {
44
- const existing = into.get(file.path);
45
- if (!existing) {
46
- into.set(file.path, { count: file.count, path: file.path, refs: [...file.refs] });
47
- return;
48
- }
49
- for (const hit of file.refs) {
50
- const same = existing.refs.find(
51
- (candidate: ReferenceHit) => candidate.refType === hit.refType && candidate.ref === hit.ref,
52
- );
53
- if (same) {
54
- same.count += hit.count;
55
- } else {
56
- existing.refs.push({ ...hit });
57
- }
58
- }
59
- existing.count += file.count;
60
- }
33
+ /** The state a caller gets for a path that names no file. */
34
+ const NO_FILE: UsageState = { message: "no media file to look for", status: "failed" };
61
35
 
62
36
  /**
63
- * One result out of several, for the same file asked about under different names.
37
+ * The query for a media file, or null when the path names nothing.
64
38
  *
65
- * The lanes cannot double-count: each asks about a DIFFERENT resolved path, and one authored string
66
- * resolves to exactly one of them. Errors are unioned by path so a document that failed to parse in
67
- * every lane is reported once, and `path` reports the media file the caller asked about rather than
68
- * whichever lane happened to be first.
39
+ * Normalizing here rather than at each call site is the whole of what this wrapper adds over
40
+ * `loadUsages`: the file tree, a drop handler and a library tile do not agree on whether a path
41
+ * carries a leading `./`, and two spellings of one file must not become two cache entries.
69
42
  */
70
- function unionResults(path: string, results: readonly ReferencesResult[]): ReferencesResult {
71
- const files = new Map<string, ReferenceFile>();
72
- const errors = new Map<string, { path: string; error: string }>();
73
- for (const result of results) {
74
- for (const file of result.files) {
75
- mergeFile(files, file);
76
- }
77
- for (const error of result.errors) {
78
- if (!errors.has(error.path)) {
79
- errors.set(error.path, error);
80
- }
81
- }
82
- }
83
- const merged = [...files.values()].toSorted((a, b) => a.path.localeCompare(b.path));
84
- return {
85
- errors: [...errors.values()],
86
- files: merged,
87
- filesReferencing: merged.length,
88
- path,
89
- refsTotal: merged.reduce((sum, file) => sum + file.count, 0),
90
- tagName: null,
91
- };
92
- }
93
-
94
- /**
95
- * Reduce the lanes to one state.
96
- *
97
- * Precedence is strictly least-informative-wins, because every step down is a step away from a
98
- * number the caller could act on: unsupported (the host cannot answer at all) beats failed (it
99
- * tried and could not) beats pending beats a real union.
100
- */
101
- function combine(path: string, states: readonly UsageState[]): UsageState {
102
- if (states.some((state) => state.status === "unsupported")) {
103
- return { status: "unsupported" };
104
- }
105
- const failure = states.find((state) => state.status === "failed");
106
- if (failure) {
107
- return failure;
108
- }
109
- if (states.some((state) => state.status === "pending")) {
110
- return { status: "pending" };
111
- }
112
- return {
113
- result: unionResults(
114
- path,
115
- states.map((state) => (state as { result: ReferencesResult }).result),
116
- ),
117
- status: "ready",
118
- };
43
+ function mediaQuery(path: string): { path: string } | null {
44
+ const normalized = normalizeProjectPath(path);
45
+ return normalized === "" ? null : { path: normalized };
119
46
  }
120
47
 
121
48
  /**
122
49
  * The answer right now, WITHOUT starting a request — the synchronous read a lit template needs.
123
50
  *
124
- * `null` means at least one lane has never been asked, and the caller decides whether this paint is
125
- * the one that asks (see {@link loadMediaUsages}).
51
+ * `null` means the question has never been asked, and the caller decides whether this paint is the
52
+ * one that asks (see {@link loadMediaUsages}).
126
53
  */
127
54
  export function peekMediaUsages(path: string): UsageState | null {
128
- const queries = mediaUsageQueries(path);
129
- if (queries.length === 0) {
130
- return null;
131
- }
132
- const states: UsageState[] = [];
133
- for (const query of queries) {
134
- const state = peekUsages(query);
135
- if (state === null) {
136
- return null;
137
- }
138
- states.push(state);
139
- }
140
- return combine(path, states);
55
+ const query = mediaQuery(path);
56
+ return query === null ? null : peekUsages(query);
141
57
  }
142
58
 
143
59
  /**
144
- * Ask every lane and union the answers. Never rejects — a failure is a STATE, because the caller
60
+ * Ask, or join the ask already in flight. Never rejects — a failure is a STATE, because the caller
145
61
  * has to render something and "unknown" is the honest something.
146
62
  */
147
63
  export async function loadMediaUsages(path: string): Promise<UsageState> {
148
- const queries = mediaUsageQueries(path);
149
- if (queries.length === 0) {
150
- return { message: "no media file to look for", status: "failed" };
151
- }
152
- return combine(path, await Promise.all(queries.map((query) => loadUsages(query))));
64
+ const query = mediaQuery(path);
65
+ return query === null ? NO_FILE : loadUsages(query);
153
66
  }
154
67
 
155
- /** Forget every lane's answer and ask again — the Retry behind a failed media count. */
68
+ /** Forget the answer and ask again — the Retry behind a failed media count. */
156
69
  export async function retryMediaUsages(path: string): Promise<UsageState> {
157
- const queries = mediaUsageQueries(path);
158
- if (queries.length === 0) {
159
- return { message: "no media file to look for", status: "failed" };
160
- }
161
- return combine(path, await Promise.all(queries.map((query) => retryUsages(query))));
70
+ const query = mediaQuery(path);
71
+ return query === null ? NO_FILE : retryUsages(query);
162
72
  }
163
73
 
164
74
  /**
@@ -19,6 +19,7 @@ import {
19
19
  formatSerialize,
20
20
  loadFormats,
21
21
  } from "../format/format-host";
22
+ import { serializeJson } from "./json-layout";
22
23
  import type { Tab } from "../tabs/tab";
23
24
 
24
25
  /**
@@ -56,5 +57,11 @@ export async function serializeDocument(tab: Tab): Promise<string> {
56
57
  });
57
58
  }
58
59
  }
59
- return JSON.stringify(tab.doc.document, null, 2);
60
+ /* Native JSON, in the layout the file was read in (`json-layout.ts`, issue 308).
61
+ `tab.doc.layout` is what the read recorded — which objects the author kept on one line, where
62
+ a blank line sits, which characters were escaped — and it is null for a document with no JSON
63
+ source, where every object expands and every array is laid by fit: the formatter's own answer
64
+ for stringified output. Either way the text ends with one newline, as every formatted file
65
+ does. */
66
+ return serializeJson(tab.doc.document, tab.doc.layout ?? null);
60
67
  }
@@ -27,6 +27,8 @@ import {
27
27
  stringProperty,
28
28
  } from "../commands/command-args";
29
29
  import { convertTargetExtensions, convertTargets } from "./format-choices";
30
+ import { parseJsonDocument, serializeJson } from "../files/json-layout";
31
+ import type { JsonLayout } from "../files/json-layout";
30
32
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
31
33
 
32
34
  /** What a conversion will do, resolved in full before the reader is asked to confirm it. */
@@ -97,7 +99,12 @@ async function writeDocument(
97
99
  ): Promise<string> {
98
100
  const merged = { ...frontmatter, ...document };
99
101
  if (targetExt === ".json") {
100
- return `${JSON.stringify(merged, null, 2)}\n`;
102
+ /* The same serializer a save uses (`files/json-layout.ts`), with NO layout: the source was
103
+ markdown or CSV, so there is no JSON text whose line breaks could be kept. Every object
104
+ expands and every short array stays on one line — which is exactly what the repository's
105
+ formatter would make of `JSON.stringify` output, so the converted file needs no reformat and
106
+ the tab it opens in reads its layout straight back. The newline is the serializer's own. */
107
+ return serializeJson(merged, null);
101
108
  }
102
109
  const { formatByExtension, formatSerialize } = await import("./format-host");
103
110
  const format = formatByExtension(targetExt, "serialize");
@@ -368,12 +375,16 @@ async function rebuildTab(from: string, to: string, text: string): Promise<void>
368
375
  const format = formatForPath(to);
369
376
  let document: Record<string, unknown>;
370
377
  let frontmatter: Record<string, unknown> | undefined;
378
+ // The layout of the JSON just written, as every other JSON reader records it (`files/files.ts`,
379
+ // `files/file-ops.ts`): the text is the serializer's own, so the record says what a layout-less
380
+ // Write would do anyway — but the tab reads its file rather than assuming it.
381
+ let layout: JsonLayout | null = null;
371
382
  try {
372
383
  if (format) {
373
384
  const { parseSourceForPath } = await import("../files/file-ops");
374
385
  ({ document, frontmatter } = await parseSourceForPath(to, text));
375
386
  } else {
376
- document = JSON.parse(text) as Record<string, unknown>;
387
+ ({ document, layout } = parseJsonDocument(text));
377
388
  }
378
389
  } catch {
379
390
  // The bytes on disk are the ones just written and the conversion has already succeeded, so a
@@ -386,6 +397,7 @@ async function rebuildTab(from: string, to: string, text: string): Promise<void>
386
397
  documentPath: to,
387
398
  ...(frontmatter === undefined ? {} : { frontmatter }),
388
399
  id: to,
400
+ layout,
389
401
  sourceFormat: format?.name ?? null,
390
402
  });
391
403
  }
@@ -485,14 +497,8 @@ export function fileFormatCommands(): AnyCommand[] {
485
497
  // Nothing restores it: the file has moved and its references have been rewritten with it.
486
498
  // The confirmation carrying the count is what stands in for an undo.
487
499
  undo: "none",
488
- aiTool: {
489
- description:
490
- "Convert a document between formats in place — Markdown to JSON and back. The file is " +
491
- "renamed to the new extension and every reference to it is rewritten. Refused for " +
492
- "layouts, for anything inside a content collection, and while the file is open with " +
493
- "unsaved changes.",
494
- name: "convert_file_format",
495
- },
500
+ /* No `aiTool`, by §12.4's second deletion rule: `run` awaits a confirm dialog the person
501
+ answers. */
496
502
  run: async (_ctx, args: Record<string, unknown>) => {
497
503
  const target = typeof args.format === "string" ? args.format : undefined;
498
504
  await convertFile(
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { setProjectSchemasForMonaco } from "../services/monaco-lazy";
11
11
  import { getPlatform } from "../platform";
12
- import type { ExtensionsInfo } from "../types";
12
+ import type { ExtensionCatalogEntry, ExtensionsInfo } from "../types";
13
13
  import type { JxMutableNode } from "@jxsuite/schema/types";
14
14
 
15
15
  export interface StudioFormatHints {
@@ -76,6 +76,8 @@ export function refreshFormats() {
76
76
  _formats = [];
77
77
  _extensionsLoaded = null;
78
78
  _extensions = [];
79
+ _catalogLoaded = null;
80
+ _catalog = [];
79
81
  }
80
82
 
81
83
  /** Seed the registry directly (tests and hosts that preload format metadata). */
@@ -122,6 +124,50 @@ export function setExtensions(extensions: ExtensionsInfo[]) {
122
124
  _extensionsLoaded = Promise.resolve(extensions);
123
125
  }
124
126
 
127
+ // ─── Extension catalogue (specs/extensions.md §9.2) ──────────────────────────
128
+ /* The AVAILABLE half beside the ENABLED half above, cached the same way and for a sharper reason:
129
+ the Extensions section and the AI assistant's system prompt both need "what could this project
130
+ turn on", and `buildSystemPrompt` is synchronous. Two caches would be two answers to one
131
+ question, so there is one, loaded here and read synchronously by both. */
132
+
133
+ let _catalog: ExtensionCatalogEntry[] = [];
134
+ let _catalogLoaded: Promise<ExtensionCatalogEntry[]> | null = null;
135
+
136
+ /**
137
+ * Load (and cache) what this backend can offer. Backed by the optional `listExtensionCatalog`
138
+ * member; a platform without it (or a failure) degrades to an empty list, and the Extensions
139
+ * section falls back to a typed package name.
140
+ *
141
+ * @returns {Promise<ExtensionCatalogEntry[]>}
142
+ */
143
+ export function loadExtensionCatalog(): Promise<ExtensionCatalogEntry[]> {
144
+ if (!_catalogLoaded) {
145
+ _catalogLoaded = (async () => {
146
+ try {
147
+ const platform = getPlatform() as {
148
+ listExtensionCatalog?: () => Promise<ExtensionCatalogEntry[]>;
149
+ };
150
+ _catalog = (await platform.listExtensionCatalog?.()) ?? [];
151
+ } catch {
152
+ _catalog = [];
153
+ }
154
+ return _catalog;
155
+ })();
156
+ }
157
+ return _catalogLoaded;
158
+ }
159
+
160
+ /** The last-loaded catalogue (synchronous access for render and prompt paths). */
161
+ export function getExtensionCatalog(): ExtensionCatalogEntry[] {
162
+ return _catalog;
163
+ }
164
+
165
+ /** Seed the catalogue directly (tests and hosts that preload it). */
166
+ export function setExtensionCatalog(catalog: ExtensionCatalogEntry[]) {
167
+ _catalog = catalog;
168
+ _catalogLoaded = Promise.resolve(catalog);
169
+ }
170
+
125
171
  /**
126
172
  * Fetch the active project's entry documents ONCE and hand the same payload to every consumer.
127
173
  *
@@ -166,6 +212,9 @@ export function refreshExtensionUi(platform: {
166
212
  fetchProjectSchemas?: () => Promise<{ project?: unknown; document?: unknown }>;
167
213
  }): void {
168
214
  void shareProjectSchemas(platform);
215
+ // `installed` and `bundled` are per-project facts, so an install or a project switch can move
216
+ // Them even when the shipped half has not changed.
217
+ void loadExtensionCatalog();
169
218
  void import("../settings/extension-sections")
170
219
  .then(({ syncExtensionSettingsSections }) => syncExtensionSettingsSections())
171
220
  .catch(() => {
@@ -34,16 +34,25 @@
34
34
  * here — the browser withholds the reason on purpose — so the detail names both rather than
35
35
  * guessing between them.
36
36
  *
37
+ * **The waiting room is a document.** `surfaces/github-auth.json` draws the code, the link and the
38
+ * wait, over the kit's `jx-dialog`; this module keeps the client id, the poll loop, its failure
39
+ * budget and every report above. The dialog it replaced was an `<sp-dialog-wrapper>` whose one
40
+ * `@cancel`/`@close` handler both stopped the loop and resolved the promise, so "the reader
41
+ * dismissed this" and "GitHub answered" were the same code path — and the promise could be resolved
42
+ * a second time with `null` by the close that a successful sign-in itself provokes. Answering and
43
+ * closing are two steps now, in that order.
44
+ *
37
45
  * The token is returned to callers and never rendered. In a browser it is stored in `localStorage`;
38
46
  * on the desktop it is in the launcher's `0600` credential store and this module holds it only in
39
47
  * memory for the session. `settings/preferences-accounts.ts` lists it as _stored or not_ and is the
40
48
  * only place it can be revoked (`studio.md` §15 rule 1).
41
49
  */
42
50
 
43
- import { html } from "lit-html";
44
51
  import { errorMessage } from "@jxsuite/schema/parse";
45
52
  import { notify } from "../services/notify";
46
- import { showDialog } from "../ui/layers";
53
+ import { layerHost } from "../ui/layers";
54
+ import { openGithubAuthSurface } from "../surfaces/github-auth";
55
+ import type { GithubAuthSurfaceHandle } from "../surfaces/github-auth";
47
56
 
48
57
  const CLIENT_ID = "Ov23liYVlMFpgjOEPXJH";
49
58
  const STORAGE_KEY = "jx_github_token";
@@ -247,17 +256,52 @@ export async function authenticateGithub() {
247
256
 
248
257
  const { device_code, user_code, verification_uri, interval = 5 } = codeData;
249
258
 
250
- return showDialog<string | null>((done) => {
259
+ return new Promise<string | null>((resolve) => {
251
260
  let cancelled = false;
252
261
  let pollTimer: ReturnType<typeof setTimeout> | null = null;
253
262
  let failures = 0;
254
-
255
- const stop = () => {
263
+ let answered = false;
264
+
265
+ /**
266
+ * Stop the loop and answer, once.
267
+ *
268
+ * Separate from {@link done} because both ends arrive and either may be first: a token that
269
+ * lands closes the dialog, which raises `onClosed` behind it, and a dialog the reader dismisses
270
+ * raises `onClosed` with no token at all. Answering here and closing there is what keeps the
271
+ * second of those from overwriting the first with `null`.
272
+ */
273
+ const settle = (token: string | null): void => {
274
+ if (answered) {
275
+ return;
276
+ }
277
+ answered = true;
256
278
  cancelled = true;
257
279
  if (pollTimer) {
258
280
  clearTimeout(pollTimer);
281
+ pollTimer = null;
282
+ }
283
+ resolve(token);
284
+ };
285
+
286
+ /**
287
+ * Take the dialog down, once.
288
+ *
289
+ * Guarded here rather than trusted to the handle, because closing is what RAISES `onClosed` —
290
+ * so a teardown that re-entered through it would call itself until the stack ran out.
291
+ */
292
+ let closing = false;
293
+ const takeDown = (): void => {
294
+ if (closing) {
295
+ return;
259
296
  }
260
- done(null);
297
+ closing = true;
298
+ handle.close();
299
+ };
300
+
301
+ /** The poll's own exit: answer, then take the dialog down. */
302
+ const done = (token: string | null): void => {
303
+ settle(token);
304
+ takeDown();
261
305
  };
262
306
 
263
307
  const poll = async () => {
@@ -306,13 +350,11 @@ export async function authenticateGithub() {
306
350
  ? "The device code expired before it was entered."
307
351
  : `GitHub answered "${tokenData.error ?? "an unrecognised response"}".`,
308
352
  );
309
- cancelled = true;
310
353
  done(null);
311
354
  } catch (error) {
312
355
  failures += 1;
313
356
  if (failures >= MAX_POLL_FAILURES) {
314
357
  reportUnreachable(error);
315
- cancelled = true;
316
358
  done(null);
317
359
  return;
318
360
  }
@@ -320,27 +362,27 @@ export async function authenticateGithub() {
320
362
  }
321
363
  };
322
364
 
323
- pollTimer = setTimeout(poll, interval * 1000);
365
+ /*
366
+ * The dialog first, then the timer. `done` reaches for `handle`, and a poll that fired before
367
+ * the surface existed would find a binding that is not initialised yet — which a zero-second
368
+ * device interval makes reachable rather than theoretical.
369
+ */
370
+ const handle: GithubAuthSurfaceHandle = openGithubAuthSurface({
371
+ layer: layerHost("dialog"),
372
+ onCancel: () => {
373
+ takeDown();
374
+ },
375
+ /* `done`, not `settle`: a `close` the flow did not ask for — Escape, or a dismissal the
376
+ platform allows — must ALSO take the document out of the dialog layer, or the surface
377
+ outlives the dialog it drew. `settle` is idempotent, so a close that follows a token
378
+ answers nothing and only cleans up. */
379
+ onClosed: () => {
380
+ done(null);
381
+ },
382
+ userCode: user_code,
383
+ verificationUri: verification_uri,
384
+ });
324
385
 
325
- return html`
326
- <sp-dialog-wrapper
327
- open
328
- headline="Sign in to GitHub"
329
- cancel-label="Cancel"
330
- @cancel=${stop}
331
- @close=${stop}
332
- >
333
- <div class="github-auth-dialog">
334
- <p>Enter this code on GitHub to authorize Jx Studio:</p>
335
- <div class="github-auth-code">${user_code}</div>
336
- <p>
337
- <a href="${verification_uri}" target="_blank" rel="noopener"
338
- >Open ${verification_uri}</a
339
- >
340
- </p>
341
- <p class="github-auth-waiting">Waiting for authorization…</p>
342
- </div>
343
- </sp-dialog-wrapper>
344
- `;
386
+ pollTimer = setTimeout(poll, interval * 1000);
345
387
  });
346
388
  }