@jxsuite/studio 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/canvas.html +21 -0
  2. package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
  3. package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
  4. package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
  5. package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
  6. package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
  7. package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
  8. package/dist/chunks/content-source-34gnkbnn.js +38 -0
  9. package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
  10. package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
  11. package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
  12. package/dist/chunks/extension-sections-6mqydz35.js +301 -0
  13. package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
  14. package/dist/chunks/files-8kn321h1.js +70 -0
  15. package/dist/chunks/files-8kn321h1.js.map +9 -0
  16. package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
  17. package/dist/chunks/git-panel-tjbr191d.js +51 -0
  18. package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
  19. package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
  20. package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
  21. package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
  22. package/dist/chunks/layers-panel-87pb25km.js +58 -0
  23. package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
  24. package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
  25. package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
  26. package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
  27. package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
  28. package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
  29. package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
  30. package/dist/chunks/right-panel-zpdxd98t.js +37 -0
  31. package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
  32. package/dist/chunks/section-registry-zmckaxf4.js +30 -0
  33. package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
  34. package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
  35. package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
  36. package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
  37. package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
  38. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
  39. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
  40. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
  41. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
  42. package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
  43. package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
  44. package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
  45. package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
  46. package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
  47. package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
  48. package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
  49. package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
  50. package/dist/chunks/studio-41exgzhq.js +6690 -0
  51. package/dist/chunks/studio-41exgzhq.js.map +38 -0
  52. package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
  53. package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
  54. package/dist/chunks/studio-50k77cca.js +1787 -0
  55. package/dist/chunks/studio-50k77cca.js.map +18 -0
  56. package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
  57. package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
  58. package/dist/chunks/studio-6f0am8f2.js +53 -0
  59. package/dist/chunks/studio-6f0am8f2.js.map +10 -0
  60. package/dist/chunks/studio-6nmjc5qk.js +7002 -0
  61. package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
  62. package/dist/chunks/studio-7afd21nw.js +67 -0
  63. package/dist/chunks/studio-7afd21nw.js.map +10 -0
  64. package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
  65. package/dist/chunks/studio-7bmdvzne.js.map +10 -0
  66. package/dist/chunks/studio-8jpzqk5s.js +128 -0
  67. package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
  68. package/dist/chunks/studio-94m77tgk.js +1482 -0
  69. package/dist/chunks/studio-94m77tgk.js.map +13 -0
  70. package/dist/chunks/studio-9je6w5sq.js +1000 -0
  71. package/dist/chunks/studio-9je6w5sq.js.map +16 -0
  72. package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
  73. package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
  74. package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
  75. package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
  76. package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
  77. package/dist/chunks/studio-bw5dz6km.js +608 -0
  78. package/dist/chunks/studio-bw5dz6km.js.map +21 -0
  79. package/dist/chunks/studio-c6s5getc.js +4232 -0
  80. package/dist/chunks/studio-c6s5getc.js.map +39 -0
  81. package/dist/chunks/studio-cjm7fdjf.js +451 -0
  82. package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
  83. package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
  84. package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
  85. package/dist/chunks/studio-dg7zyt5x.js +28 -0
  86. package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
  87. package/dist/chunks/studio-dzcyvvvz.js +166 -0
  88. package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
  89. package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
  90. package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
  91. package/dist/chunks/studio-f12h6177.js +411 -0
  92. package/dist/chunks/studio-f12h6177.js.map +13 -0
  93. package/dist/chunks/studio-hbp1s8m9.js +1817 -0
  94. package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
  95. package/dist/chunks/studio-k2sxjph5.js +15295 -0
  96. package/dist/chunks/studio-k2sxjph5.js.map +235 -0
  97. package/dist/chunks/studio-myje51t3.js +385 -0
  98. package/dist/chunks/studio-myje51t3.js.map +12 -0
  99. package/dist/chunks/studio-na6rwzhw.js +353 -0
  100. package/dist/chunks/studio-na6rwzhw.js.map +11 -0
  101. package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
  102. package/dist/chunks/studio-p471gg5n.js.map +14 -0
  103. package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
  104. package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
  105. package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
  106. package/dist/chunks/studio-sas7mt3k.js +75 -0
  107. package/dist/chunks/studio-sas7mt3k.js.map +10 -0
  108. package/dist/chunks/studio-t5wqwzdh.js +74 -0
  109. package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
  110. package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
  111. package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
  112. package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
  113. package/dist/chunks/studio-tr20m8g8.js.map +9 -0
  114. package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
  115. package/dist/chunks/studio-v96qfnww.js.map +54 -0
  116. package/dist/chunks/studio-vcetc91k.js +659 -0
  117. package/dist/chunks/studio-vcetc91k.js.map +10 -0
  118. package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
  119. package/dist/chunks/studio-vmymjefp.js.map +98 -0
  120. package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
  121. package/dist/chunks/studio-x9hmy5kr.js +390 -0
  122. package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
  123. package/dist/chunks/studio-xa0ce0n7.js +335 -0
  124. package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
  125. package/dist/chunks/studio-xm3dbxvn.js +378 -0
  126. package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
  127. package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
  128. package/dist/chunks/studio-zv37yrfa.js +1054 -0
  129. package/dist/chunks/studio-zv37yrfa.js.map +13 -0
  130. package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
  131. package/dist/chunks/ws-client-654ts66j.js.map +11 -0
  132. package/dist/iframe-entry.js +668 -230
  133. package/dist/studio.js +23711 -35185
  134. package/index.html +35 -4685
  135. package/package.json +17 -15
  136. package/src/about/about-modal.ts +42 -11
  137. package/src/browse/library-commands.ts +240 -0
  138. package/src/browse/library-layouts.ts +369 -0
  139. package/src/browse/library-model.ts +396 -0
  140. package/src/browse/library-pane.ts +1049 -0
  141. package/src/browse/library-preview.ts +252 -0
  142. package/src/browse/library-source.ts +150 -0
  143. package/src/canvas/canvas-helpers.ts +33 -9
  144. package/src/canvas/canvas-live-render.ts +45 -29
  145. package/src/canvas/canvas-patcher.ts +151 -31
  146. package/src/canvas/canvas-perf.ts +46 -7
  147. package/src/canvas/canvas-render.ts +1092 -220
  148. package/src/canvas/canvas-surface.ts +240 -0
  149. package/src/canvas/canvas-utils.ts +1166 -124
  150. package/src/canvas/iframe-drop.ts +2 -1
  151. package/src/canvas/iframe-entry.ts +241 -4
  152. package/src/canvas/iframe-host.ts +1226 -143
  153. package/src/canvas/iframe-inline-edit.ts +31 -0
  154. package/src/canvas/iframe-interaction.ts +76 -16
  155. package/src/canvas/iframe-keys.ts +107 -45
  156. package/src/canvas/iframe-overlay.ts +38 -1
  157. package/src/canvas/iframe-protocol.ts +137 -2
  158. package/src/canvas/iframe-render.ts +70 -2
  159. package/src/canvas/iframe-slash.ts +6 -0
  160. package/src/canvas/path-mapping.ts +56 -6
  161. package/src/canvas/surface-registry.ts +292 -0
  162. package/src/collab/collab-commands.ts +244 -0
  163. package/src/collab/collab-session.ts +198 -32
  164. package/src/collab/collab-state.ts +28 -2
  165. package/src/collab/presence-chips.ts +100 -9
  166. package/src/commands/active-registry.ts +42 -0
  167. package/src/commands/app-commands.ts +176 -0
  168. package/src/commands/budget.ts +158 -0
  169. package/src/commands/command-args.ts +253 -0
  170. package/src/commands/context.ts +387 -0
  171. package/src/commands/defaults.ts +580 -0
  172. package/src/commands/keymap.ts +571 -0
  173. package/src/commands/levels.ts +345 -0
  174. package/src/commands/live-context.ts +193 -0
  175. package/src/commands/reference.ts +227 -0
  176. package/src/commands/registry.ts +293 -0
  177. package/src/component-props.ts +3 -2
  178. package/src/content/draft-state.ts +106 -0
  179. package/src/content/entry-commands.ts +282 -0
  180. package/src/content/entry-editor.ts +327 -0
  181. package/src/content/entry-fields.ts +116 -0
  182. package/src/content/entry-model.ts +175 -0
  183. package/src/editor/canvas-context-menu.ts +17 -11
  184. package/src/editor/canvas-slash-bridge.ts +11 -4
  185. package/src/editor/context-menu.ts +804 -204
  186. package/src/editor/convert-to-component.ts +31 -10
  187. package/src/editor/convert-to-repeater.ts +3 -2
  188. package/src/editor/inline-edit-apply.ts +5 -5
  189. package/src/editor/inline-edit.ts +86 -50
  190. package/src/editor/insert-zone-action.ts +1 -1
  191. package/src/editor/shortcuts.ts +1043 -329
  192. package/src/editor/slash-menu.ts +1 -0
  193. package/src/files/elements.ts +166 -0
  194. package/src/files/file-ops.ts +178 -31
  195. package/src/files/files.ts +898 -268
  196. package/src/files/fs-events.ts +21 -0
  197. package/src/files/media-meta.ts +203 -0
  198. package/src/files/media-paths.ts +141 -0
  199. package/src/files/media-upload.ts +7 -3
  200. package/src/files/media-usage.ts +189 -0
  201. package/src/github/github-auth.ts +235 -33
  202. package/src/github/github-publish.ts +80 -21
  203. package/src/grid/grid-controller.ts +152 -12
  204. package/src/grid/grid-layout.ts +225 -20
  205. package/src/grid/grid-open.ts +120 -0
  206. package/src/grid/grid-panel.ts +554 -39
  207. package/src/grid/grid-source.ts +27 -1
  208. package/src/grid/redirects-grid.ts +599 -0
  209. package/src/grid/redirects.ts +398 -0
  210. package/src/grid/sources/content-source.ts +108 -2
  211. package/src/i18n/i18n-commands.ts +322 -0
  212. package/src/new-project/add-repo-modal.ts +8 -10
  213. package/src/new-project/import-tab.ts +34 -9
  214. package/src/new-project/location-fields.ts +9 -1
  215. package/src/new-project/new-project-modal.ts +270 -262
  216. package/src/packages/jxsuite-update.ts +97 -48
  217. package/src/packages/pull-package-sync.ts +18 -9
  218. package/src/page-params.ts +2 -1
  219. package/src/panels/activity-bar.ts +152 -91
  220. package/src/panels/activity-panel.ts +481 -0
  221. package/src/panels/ai-chat/chat-markdown.ts +8 -3
  222. package/src/panels/ai-chat/chat-view.ts +245 -18
  223. package/src/panels/ai-chat/composer.ts +31 -5
  224. package/src/panels/ai-chat/sessions-view.ts +17 -10
  225. package/src/panels/ai-panel.ts +279 -120
  226. package/src/panels/block-action-bar.ts +1115 -224
  227. package/src/panels/bottom-dock.ts +337 -0
  228. package/src/panels/canvas-dnd-bridge.ts +37 -8
  229. package/src/panels/chat-panel.ts +29 -12
  230. package/src/panels/data-explorer.ts +254 -112
  231. package/src/panels/data-grid.ts +10 -4
  232. package/src/panels/dnd.ts +28 -51
  233. package/src/panels/editors.ts +434 -107
  234. package/src/panels/elements-panel.ts +66 -2
  235. package/src/panels/empty-state.ts +112 -0
  236. package/src/panels/events-panel.ts +596 -82
  237. package/src/panels/formula-workspace.ts +408 -218
  238. package/src/panels/frontmatter-fields.ts +51 -10
  239. package/src/panels/frontmatter-panel.ts +357 -79
  240. package/src/panels/git-panel.ts +375 -164
  241. package/src/panels/head-panel.ts +791 -85
  242. package/src/panels/i18n-panel.ts +592 -0
  243. package/src/panels/imports-panel.ts +95 -85
  244. package/src/panels/jump-bar.ts +584 -0
  245. package/src/panels/layers-panel.ts +1106 -328
  246. package/src/panels/left-panel.ts +109 -204
  247. package/src/panels/navigator-panels.ts +131 -0
  248. package/src/panels/overlays.ts +7 -2
  249. package/src/panels/pane-context.ts +1477 -0
  250. package/src/panels/pane-grid.ts +406 -0
  251. package/src/panels/panel-registry.ts +340 -0
  252. package/src/panels/panel-scheduler.ts +75 -0
  253. package/src/panels/problems-panel.ts +234 -0
  254. package/src/panels/properties-panel.ts +946 -1139
  255. package/src/panels/provenance.ts +258 -0
  256. package/src/panels/quick-search.ts +791 -122
  257. package/src/panels/right-panel.ts +228 -102
  258. package/src/panels/seo-modal.ts +395 -0
  259. package/src/panels/settings-pane.ts +203 -0
  260. package/src/panels/signals-panel.ts +354 -137
  261. package/src/panels/statement-editor.ts +41 -25
  262. package/src/panels/statusbar.ts +342 -106
  263. package/src/panels/style-panel.ts +974 -463
  264. package/src/panels/style-utils.ts +3 -3
  265. package/src/panels/stylebook-doc.ts +4 -2
  266. package/src/panels/stylebook-layers-panel.ts +3 -2
  267. package/src/panels/stylebook-panel.ts +51 -26
  268. package/src/panels/tab-strip.ts +1058 -78
  269. package/src/panels/target-line.ts +274 -0
  270. package/src/panels/toolbar.ts +631 -484
  271. package/src/panels/welcome-screen.ts +301 -198
  272. package/src/platform-errors.ts +26 -3
  273. package/src/platform.ts +96 -2
  274. package/src/platforms/cloud.ts +71 -8
  275. package/src/platforms/devserver.ts +92 -29
  276. package/src/publish/deploy-checklist.ts +383 -0
  277. package/src/publish/pages-service.ts +10 -1
  278. package/src/publish/publish-commands.ts +218 -0
  279. package/src/publish/publish-panel.ts +110 -16
  280. package/src/recent-projects.ts +3 -2
  281. package/src/services/a11y-report.ts +505 -0
  282. package/src/services/ai-models.ts +75 -2
  283. package/src/services/ai-project-tools.ts +29 -10
  284. package/src/services/ai-system-prompt.ts +53 -14
  285. package/src/services/ai-tools.ts +39 -3
  286. package/src/services/ai-writes.ts +154 -0
  287. package/src/services/announce.ts +97 -0
  288. package/src/services/automation.ts +424 -175
  289. package/src/services/cem-export.ts +9 -4
  290. package/src/services/clock.ts +61 -0
  291. package/src/services/document-assistant.ts +36 -8
  292. package/src/services/idle.ts +179 -0
  293. package/src/services/import-client.ts +26 -0
  294. package/src/services/monaco-buffer.ts +627 -0
  295. package/src/services/monaco-lazy.ts +36 -0
  296. package/src/services/notify.ts +271 -0
  297. package/src/services/profile.ts +155 -0
  298. package/src/services/references.ts +0 -0
  299. package/src/services/token-lint.ts +3 -2
  300. package/src/services/tool-executor.ts +53 -7
  301. package/src/services/trusted-types.ts +123 -0
  302. package/src/settings/contexts-section.ts +427 -0
  303. package/src/settings/contributed-section.ts +149 -11
  304. package/src/settings/css-vars-editor.ts +306 -349
  305. package/src/settings/defs-editor.ts +93 -34
  306. package/src/settings/dependencies-editor.ts +7 -7
  307. package/src/settings/extension-sections.ts +37 -5
  308. package/src/settings/general-settings.ts +204 -121
  309. package/src/settings/locales-section.ts +347 -0
  310. package/src/settings/preferences-accounts.ts +140 -0
  311. package/src/settings/preferences-dialog.ts +620 -0
  312. package/src/settings/preferences-keymap.ts +270 -0
  313. package/src/settings/project-sections.ts +260 -0
  314. package/src/settings/section-registry.ts +169 -0
  315. package/src/settings/settings-document.ts +385 -0
  316. package/src/shell.ts +1549 -0
  317. package/src/site-context.ts +45 -20
  318. package/src/state.ts +14 -275
  319. package/src/store.ts +88 -43
  320. package/src/studio.ts +790 -346
  321. package/src/style/live-preview.ts +36 -0
  322. package/src/style/project-styles.ts +349 -0
  323. package/src/style/token-ref.ts +123 -0
  324. package/src/tabs/patch-ops.ts +16 -4
  325. package/src/tabs/project-config.ts +416 -0
  326. package/src/tabs/selection.ts +323 -0
  327. package/src/tabs/tab.ts +182 -47
  328. package/src/tabs/transact.ts +209 -28
  329. package/src/types.ts +68 -13
  330. package/src/ui/ai-credentials-form.ts +39 -35
  331. package/src/ui/ai-managed-connect.ts +113 -0
  332. package/src/ui/dynamic-slot.ts +224 -81
  333. package/src/ui/expression-editor.ts +71 -63
  334. package/src/ui/field-input.ts +4 -6
  335. package/src/ui/field-row.ts +215 -38
  336. package/src/ui/form-controls.ts +194 -7
  337. package/src/ui/layers.ts +492 -69
  338. package/src/ui/media-picker.ts +115 -25
  339. package/src/ui/panel-resize.ts +109 -91
  340. package/src/ui/progress-modal.ts +131 -50
  341. package/src/ui/regions.ts +462 -0
  342. package/src/ui/schema-form.ts +229 -45
  343. package/src/ui/spectrum.ts +24 -8
  344. package/src/ui/timing.ts +49 -0
  345. package/src/ui/value-selector.ts +20 -0
  346. package/src/ui/value-source.ts +348 -0
  347. package/src/ui/virtual-window.ts +400 -0
  348. package/src/utils/edit-display.ts +3 -2
  349. package/src/utils/inherited-style.ts +67 -37
  350. package/src/view.ts +64 -78
  351. package/src/workspace/pane-derive.ts +1258 -0
  352. package/src/workspace/session.ts +317 -0
  353. package/src/workspace/workspace.ts +1345 -23
  354. package/styles/canvas.css +653 -0
  355. package/styles/forced-colors.css +106 -0
  356. package/styles/inspector.css +1454 -0
  357. package/styles/overlays.css +2704 -0
  358. package/styles/panels.css +1701 -0
  359. package/styles/shell.css +1423 -0
  360. package/styles/tokens.css +151 -0
  361. package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
  362. package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
  363. package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
  364. package/dist/chunks/files-02zn5y24.js +0 -50
  365. package/dist/chunks/files-02zn5y24.js.map +0 -9
  366. package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
  367. package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
  368. package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
  369. package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
  370. package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
  371. package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
  372. package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
  373. package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
  374. package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
  375. package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
  376. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
  377. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
  378. package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
  379. package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
  380. package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
  381. package/dist/chunks/studio-568nx4t5.js +0 -469
  382. package/dist/chunks/studio-568nx4t5.js.map +0 -14
  383. package/dist/chunks/studio-9smfzqhc.js +0 -19
  384. package/dist/chunks/studio-9smfzqhc.js.map +0 -10
  385. package/dist/chunks/studio-asvf0j9e.js +0 -429
  386. package/dist/chunks/studio-asvf0j9e.js.map +0 -13
  387. package/dist/chunks/studio-d77qm3pk.js +0 -3427
  388. package/dist/chunks/studio-d77qm3pk.js.map +0 -26
  389. package/dist/chunks/studio-j6gqyjf4.js +0 -1854
  390. package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
  391. package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
  392. package/dist/chunks/studio-qkvt37c0.js.map +0 -9
  393. package/dist/chunks/studio-rq0vxb19.js +0 -3744
  394. package/dist/chunks/studio-rq0vxb19.js.map +0 -22
  395. package/dist/chunks/studio-wd6ewdvd.js +0 -853
  396. package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
  397. package/dist/chunks/studio-xq0t7n5t.js +0 -140
  398. package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
  399. package/dist/chunks/studio-xze4zrs1.js.map +0 -10
  400. package/dist/chunks/studio-ygzav7z5.js.map +0 -46
  401. package/dist/chunks/studio-zmy7241e.js +0 -399
  402. package/dist/chunks/studio-zmy7241e.js.map +0 -12
  403. package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
  404. package/src/browse/browse-modal.ts +0 -69
  405. package/src/browse/browse.ts +0 -904
  406. package/src/canvas/canvas-diff.ts +0 -216
  407. package/src/canvas/nested-site-style.ts +0 -58
  408. package/src/new-project/design-fields.ts +0 -264
  409. package/src/new-project/templates.ts +0 -61
  410. package/src/panels/tab-bar.ts +0 -548
  411. package/src/settings/settings-modal.ts +0 -203
  412. /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
  413. /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
  414. /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
  415. /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
  416. /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
  417. /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
  418. /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
  419. /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
@@ -0,0 +1,416 @@
1
+ /// <reference lib="dom" />
2
+ /**
3
+ * The project configuration document — `project.json` under the transaction log.
4
+ *
5
+ * `project.json` is the file that defines the project, and until now it was the one file Studio
6
+ * edited with no document behind it. Twenty-nine call sites across eight modules each reached for
7
+ * `platform.writeFile("project.json", …)` (directly or through `updateSiteConfig`), in two
8
+ * different serialisations, with no history and no dirty flag — and twenty-one of them dropped a
9
+ * rejected write on the floor, leaving the form showing a value that was never persisted.
10
+ *
11
+ * This module is the one door. Every configuration write is now a TRANSACTION on a real {@link Tab}
12
+ * whose `documentPath` is `project.json`, which is what buys undo, the dirty flag and ⌘S from the
13
+ * machinery every other document already uses (`tabs/transact.ts`). `tab.ts`'s `inferModes` has
14
+ * always answered `["stylebook", "source"]` for this path, so the tab's editor kind is `config`
15
+ * (see `editorKindForMode`) with no new wiring.
16
+ *
17
+ * **The document of record.** When the author has `project.json` open in the workspace, THAT tab is
18
+ * the configuration document: the settings surfaces and the open tab edit one object, so neither
19
+ * can silently clobber the other. When it is not open the module keeps a document of its own, with
20
+ * the same log, and hands over the moment a tab appears. One rule, stated once:
21
+ * `projectState.projectConfig` is always `toRaw(document.doc.document)`.
22
+ *
23
+ * **One object, and a handover that cannot lose an edit.** That rule is restored at the moment a
24
+ * tab is adopted, and adoption is reached lazily — from inside a commit. So a `project.json` tab
25
+ * opened from the Files tree (`files/files.ts` parses the file itself) arrives holding a SECOND
26
+ * configuration object, and until the next commit the settings surfaces are still rendering, and
27
+ * mutating in place, the one they were loaded with. {@link commitProjectConfig} therefore reads the
28
+ * live configuration BEFORE it binds and commits THAT object's content, adopting it into the
29
+ * document; the alternative — letting the tab's parse win because it happened to bind last —
30
+ * dropped the first settings edit after the tab was opened, wrote the drop to disk, and reported
31
+ * success. When the document holds unsaved authoring of its own the two cannot be reconciled, and
32
+ * §16 gets a Problem instead of a silent winner. {@link adoptProjectConfig} is the same handover
33
+ * from the other side: a config that reached disk without passing through here (the assistant's
34
+ * `write_file`) is put INTO the document rather than left beside it as a rival.
35
+ *
36
+ * **One serialisation.** {@link serializeProjectConfig} is `JSON.stringify(config, null, 2)` —
37
+ * byte-for-byte what `files/file-ops.ts`'s native-JSON branch writes, so a ⌘S on the open tab and a
38
+ * settings edit produce the same file. The predecessor had `null, 2` in `site-context.ts` and
39
+ * `"\t"` in both `settings/contributed-section.ts` and `settings/defs-editor.ts`, so a settings
40
+ * edit re-indented the entire file — every `project.json` in this repository is on disk with two
41
+ * spaces.
42
+ *
43
+ * **A no-op edit writes nothing.** A form that re-commits the value it already holds — and every
44
+ * one of these surfaces has such a path — used to rewrite the whole file. A commit now compares the
45
+ * serialised result against what the file itself says and returns without a transaction, without a
46
+ * write, and therefore with an empty diff.
47
+ *
48
+ * **Collaboration.** `project.json` is out of collab replication; the gate is in
49
+ * `collab/collab-session.ts`'s `ensureCollab`, which is what would otherwise register the Yjs
50
+ * history delegate over this tab.
51
+ */
52
+
53
+ import { errorMessage } from "@jxsuite/schema/parse";
54
+ import { effect, toRaw } from "../reactivity";
55
+ import { getPlatform } from "../platform";
56
+ import { notify } from "../services/notify";
57
+ import { requireProjectState, setProjectState } from "../state";
58
+ import { setWorkspaceProject, workspace } from "../workspace/workspace";
59
+ import { PROJECT_CONFIG_PATH, createTab, disposeTab } from "./tab";
60
+ import { transactDoc } from "./transact";
61
+
62
+ import type { Tab } from "./tab";
63
+ import type { ProjectConfig } from "@jxsuite/schema/types";
64
+
65
+ export { PROJECT_CONFIG_PATH } from "./tab";
66
+
67
+ /**
68
+ * The project configuration, as a file.
69
+ *
70
+ * The ONE serialisation. Identical to the native-JSON branch of `files/file-ops.ts`'s
71
+ * `serializeDocument`, which is what ⌘S on the open `project.json` tab goes through — the two must
72
+ * agree or every save would fight the last one.
73
+ *
74
+ * @param {ProjectConfig} config
75
+ * @returns {string}
76
+ */
77
+ export function serializeProjectConfig(config: ProjectConfig): string {
78
+ return JSON.stringify(config, null, 2);
79
+ }
80
+
81
+ // ─── The document of record ───────────────────────────────────────────────────
82
+
83
+ /** The bound configuration document, or null before the first bind. */
84
+ let _bound: Tab | null = null;
85
+
86
+ /** The document this module owns while no `project.json` tab is open. */
87
+ let _detached: Tab | null = null;
88
+
89
+ /**
90
+ * What the FILE says, re-serialised through {@link serializeProjectConfig}.
91
+ *
92
+ * Read from disk once per binding rather than assumed from the config in memory, because by the
93
+ * time a commit arrives the caller has usually already mutated that config in place — the CSS
94
+ * variables editor writes into `config.style` and then hands the same object over as a patch. A
95
+ * value taken from memory would call every one of those edits a no-op.
96
+ *
97
+ * Comparing two `JSON.stringify(_, null, 2)` renderings of the same key order is a SEMANTIC test,
98
+ * not a textual one, which is the point: `project.json` on disk is formatted by `oxfmt` (two-space
99
+ * indent, short arrays kept on one line), so a byte comparison against the file would call every
100
+ * edit a change and rewrite the whole file. This calls it unchanged and writes nothing.
101
+ *
102
+ * `null` means "unknown" — no project file, or one that would not parse — and every commit writes.
103
+ */
104
+ let _committed: string | null = null;
105
+
106
+ /** Whether {@link _committed} has been sought for the current binding. One read per project. */
107
+ let _seeding: Promise<void> | null = null;
108
+
109
+ /**
110
+ * The `project.json` tab the author has open, if any.
111
+ *
112
+ * Unwrapped, because `workspace.tabs` is a reactive Map and hands out a proxy: identity is how this
113
+ * module decides whether to rebind, and the raw object is the identity every other tab-keyed
114
+ * structure in Studio uses (`collab-session.ts`'s `rawTab` for the same reason).
115
+ */
116
+ function openConfigTab(): Tab | null {
117
+ const tab = workspace.tabs.get(PROJECT_CONFIG_PATH);
118
+ return tab ? (toRaw(tab as unknown as object) as Tab) : null;
119
+ }
120
+
121
+ /** Drop the current binding, disposing the detached document if that is what it was. */
122
+ function unbind(): void {
123
+ if (_detached) {
124
+ disposeTab(_detached);
125
+ _detached = null;
126
+ }
127
+ _bound = null;
128
+ _committed = null;
129
+ _seeding = null;
130
+ }
131
+
132
+ /** Learn what the file holds, once per binding. Memoised on the promise so commits cannot race. */
133
+ function seedCommitted(): Promise<void> {
134
+ _seeding ??= (async () => {
135
+ try {
136
+ const text = await getPlatform().readFile(PROJECT_CONFIG_PATH);
137
+ _committed = serializeProjectConfig(JSON.parse(text) as ProjectConfig);
138
+ } catch {
139
+ // No file, an unreadable one, or one that does not parse. "Unknown" is the honest answer,
140
+ // And an unknown file is one every commit must write.
141
+ _committed = null;
142
+ }
143
+ })();
144
+ return _seeding;
145
+ }
146
+
147
+ /**
148
+ * Forget the configuration document — the project-switch and test hook.
149
+ *
150
+ * Also reached implicitly: {@link projectConfigDocument} rebinds whenever the project state stops
151
+ * pointing at the bound document, which is what a reload or a second project does.
152
+ */
153
+ export function resetProjectConfigDocument(): void {
154
+ unbind();
155
+ }
156
+
157
+ /**
158
+ * Keep `projectState` and the workspace pointing at the document.
159
+ *
160
+ * Called from the bind effect rather than from the commit, so it is equally true after an undo: ⌘Z
161
+ * on the open `project.json` tab replaces the document root, and the app's live configuration has
162
+ * to follow it or the canvas would keep rendering the state the author just took back.
163
+ *
164
+ * @param {ProjectConfig} config
165
+ */
166
+ function syncProjectState(config: ProjectConfig): void {
167
+ const state = requireProjectState();
168
+ if (state.projectConfig === config) {
169
+ return;
170
+ }
171
+ setProjectState({ ...state, projectConfig: config });
172
+ setWorkspaceProject(workspace.projectRoot, config);
173
+ }
174
+
175
+ /**
176
+ * The configuration object the app is live on, unwrapped, or `null` before a project has one.
177
+ *
178
+ * Read at the TOP of a commit, before {@link projectConfigDocument} can rebind: this is the object
179
+ * the settings surfaces rendered from and mutated in place, and after a rebind it may no longer be
180
+ * the one `projectState` points at.
181
+ *
182
+ * @returns {ProjectConfig | null}
183
+ */
184
+ function liveConfig(): ProjectConfig | null {
185
+ const config = requireProjectState()?.projectConfig;
186
+ return config ? (toRaw(config as unknown as object) as ProjectConfig) : null;
187
+ }
188
+
189
+ /**
190
+ * Make `target` hold exactly `source`'s keys — assignment alone would leave the removals behind.
191
+ *
192
+ * @param {Record<string, unknown>} target
193
+ * @param {ProjectConfig} source
194
+ */
195
+ function replaceContents(target: Record<string, unknown>, source: ProjectConfig): void {
196
+ for (const key of Object.keys(target)) {
197
+ if (!Object.hasOwn(source, key)) {
198
+ delete target[key];
199
+ }
200
+ }
201
+ Object.assign(target, source);
202
+ }
203
+
204
+ /**
205
+ * Adopt `tab` as the configuration document and install the state-sync effect in its scope.
206
+ *
207
+ * @param {Tab} tab
208
+ * @returns {Tab}
209
+ */
210
+ function bind(tab: Tab): Tab {
211
+ _bound = tab;
212
+ tab.scope.run(() => {
213
+ effect(() => {
214
+ const doc = tab.doc.document;
215
+ if (_bound !== tab || !requireProjectState()) {
216
+ return;
217
+ }
218
+ syncProjectState(toRaw(doc) as unknown as ProjectConfig);
219
+ });
220
+ });
221
+ return tab;
222
+ }
223
+
224
+ /**
225
+ * The configuration document, bound on demand.
226
+ *
227
+ * Rebinding is driven by two observations rather than by a lifecycle callback nobody would remember
228
+ * to call: the workspace's `project.json` tab appearing or going away, and the project state
229
+ * ceasing to point at the bound document (a project switch, or a reload that re-parsed the file).
230
+ *
231
+ * @returns {Tab}
232
+ */
233
+ export function projectConfigDocument(): Tab {
234
+ const state = requireProjectState();
235
+ const open = openConfigTab();
236
+ if (
237
+ _bound &&
238
+ (_bound !== (open ?? _detached) || toRaw(_bound.doc.document) !== state.projectConfig)
239
+ ) {
240
+ unbind();
241
+ }
242
+ if (_bound) {
243
+ return _bound;
244
+ }
245
+ if (open) {
246
+ return bind(open);
247
+ }
248
+ _detached = createTab({
249
+ document: (state.projectConfig ?? {}) as unknown as Record<string, unknown>,
250
+ documentPath: PROJECT_CONFIG_PATH,
251
+ id: PROJECT_CONFIG_PATH,
252
+ });
253
+ return bind(_detached);
254
+ }
255
+
256
+ // ─── The chokepoint ───────────────────────────────────────────────────────────
257
+
258
+ /** What a commit did. A write failure is reported, never thrown — the caller decides the tier. */
259
+ export interface ProjectConfigCommit {
260
+ ok: boolean;
261
+ /** The platform's rejection, when the write failed. */
262
+ error?: unknown;
263
+ }
264
+
265
+ /** Extensions, as a comparable value — the enabled-extension surface gate. */
266
+ function extensionsKey(config: ProjectConfig): string {
267
+ return JSON.stringify(config.extensions ?? null);
268
+ }
269
+
270
+ /** Rebuild the format registry and the contributed settings sections after an `extensions` edit. */
271
+ async function refreshExtensionSurfaces(): Promise<void> {
272
+ const { loadFormats, refreshExtensionUi, refreshFormats } = await import("../format/format-host");
273
+ refreshFormats();
274
+ void loadFormats();
275
+ refreshExtensionUi(getPlatform());
276
+ }
277
+
278
+ /**
279
+ * Commit the project configuration: one transaction, one serialisation, one error path.
280
+ *
281
+ * Two calling styles, because the surfaces have two shapes. Pass a `patch` and its top-level keys
282
+ * are merged onto the document (a value of `undefined` CLEARS the key — `JSON.stringify` drops it,
283
+ * which is how General Settings removes a production URL). Pass nothing and the caller has already
284
+ * mutated the live configuration in place, which is what the master-detail editors do; the empty
285
+ * transaction is what puts that mutation into the log.
286
+ *
287
+ * Either way the object committed is the one the CALLER was editing, read before the bind: a
288
+ * `project.json` tab that appeared since the last commit is adopted here, and adopting it repoints
289
+ * `projectState.projectConfig` at the tab's own parse of the file. Committing the document instead
290
+ * would silently discard whatever the form had just written into the object it rendered from. The
291
+ * two are one object again by the time this returns.
292
+ *
293
+ * A failed write leaves the document dirty and files a Problem (§16): it is about a named file and
294
+ * it must be fixed, so it belongs in a list that keeps it rather than a toast that erases it. ⌘S on
295
+ * the `project.json` tab is the retry, and it writes the same bytes this does. A commit that cannot
296
+ * be applied at all — an edited configuration meeting a document with unsaved authoring of its own
297
+ * — files the same kind of Problem and writes nothing, because picking a winner is what made the
298
+ * loss silent in the first place.
299
+ *
300
+ * @param {Partial<ProjectConfig>} [patch]
301
+ * @returns {Promise<ProjectConfigCommit>}
302
+ */
303
+ export async function commitProjectConfig(
304
+ patch?: Partial<ProjectConfig>,
305
+ ): Promise<ProjectConfigCommit> {
306
+ // Before the bind, not after it: adopting a `project.json` tab repoints `projectState` at the
307
+ // Tab's own parse, and the caller has already mutated the object it rendered from.
308
+ const live = liveConfig();
309
+ const tab = projectConfigDocument();
310
+ await seedCommitted();
311
+ const current = toRaw(tab.doc.document) as unknown as ProjectConfig;
312
+ const currentText = serializeProjectConfig(current);
313
+
314
+ // Two objects that disagree — whichever one loses, an edit written into it is lost. Null when
315
+ // There is one object, or two saying the same thing, which is every commit after the first.
316
+ const rival =
317
+ live && live !== current && serializeProjectConfig(live) !== currentText ? live : null;
318
+
319
+ if (rival && tab.doc.dirty) {
320
+ /* The document holds unsaved authoring of its own — the source editor's, since a successful
321
+ commit always leaves it clean — and the live configuration holds an edit the document has
322
+ never seen. Applying either one discards the other, so neither is applied: §16 files the
323
+ write that cannot be applied, which is the one outcome silence is not allowed to be.
324
+ `ai-project-tools.ts`'s `write_file` refuses a dirty tab on exactly these grounds. */
325
+ const error = new Error(`${PROJECT_CONFIG_PATH} has unsaved changes in its editor tab`);
326
+ notify.error(
327
+ `Could not save ${PROJECT_CONFIG_PATH} — the file is open with unsaved changes. Save or ` +
328
+ `revert that tab, then make the settings change again.`,
329
+ { key: `save:${PROJECT_CONFIG_PATH}`, path: PROJECT_CONFIG_PATH, source: "Settings" },
330
+ );
331
+ return { error, ok: false };
332
+ }
333
+
334
+ const base = rival ?? current;
335
+ const next = patch ? ({ ...base, ...patch } as ProjectConfig) : base;
336
+ const text = serializeProjectConfig(next);
337
+
338
+ // Nothing the file does not already say: no transaction, no write, and therefore no diff. The
339
+ // Dirty conjunct is what makes a retry after a failed write always write; the rival conjunct is
340
+ // What keeps the handover from being skipped when the file already agrees with the live config
341
+ // But the DOCUMENT does not.
342
+ if (!rival && !tab.doc.dirty && text === _committed) {
343
+ return { ok: true };
344
+ }
345
+
346
+ const before = extensionsKey(current);
347
+ transactDoc(tab, (t) => {
348
+ const doc = t.doc.document as unknown as Record<string, unknown>;
349
+ if (rival) {
350
+ replaceContents(doc, rival);
351
+ }
352
+ for (const [key, value] of Object.entries(patch ?? {})) {
353
+ doc[key] = value;
354
+ }
355
+ });
356
+
357
+ // Serialised from what the transaction actually LANDED, not from the `next` computed above: a
358
+ // Gate on `transactDoc` can refuse a mutation, and writing the value it refused would put the
359
+ // File and the document into the one disagreement this module exists to make impossible.
360
+ const config = toRaw(tab.doc.document) as unknown as ProjectConfig;
361
+ const output = serializeProjectConfig(config);
362
+ try {
363
+ await getPlatform().writeFile(PROJECT_CONFIG_PATH, output);
364
+ } catch (error) {
365
+ notify.error(`Could not save ${PROJECT_CONFIG_PATH} — ${errorMessage(error)}`, {
366
+ key: `save:${PROJECT_CONFIG_PATH}`,
367
+ path: PROJECT_CONFIG_PATH,
368
+ source: "Settings",
369
+ });
370
+ return { error, ok: false };
371
+ }
372
+ _committed = output;
373
+ tab.doc.dirty = false;
374
+ if (extensionsKey(config) !== before) {
375
+ await refreshExtensionSurfaces();
376
+ }
377
+ return { ok: true };
378
+ }
379
+
380
+ /**
381
+ * Adopt a configuration that is ALREADY on disk into the document.
382
+ *
383
+ * The other direction of the handover. `services/ai-project-tools.ts`'s `write_file` writes
384
+ * `project.json` straight to the platform — it has to, the model authors the whole file as text —
385
+ * and then has to tell the app what it wrote. Announcing it by constructing a fresh object and
386
+ * assigning it to `projectState.projectConfig` is what left a rival beside the document: the next
387
+ * settings commit read the document, which still held the PREVIOUS configuration, and persisted the
388
+ * assistant's write back out of existence. Putting the bytes into the document instead keeps the
389
+ * one-object rule true, and the state sync follows from the bind effect like every other change.
390
+ *
391
+ * `skipHistory`, because this is a RELOAD and not an edit: the file already says this, and
392
+ * `write_file` tells the model in as many words that its disk writes are not undoable. A history
393
+ * entry here would offer ⌘Z a change it could not take back from the file.
394
+ *
395
+ * @param {ProjectConfig} config The configuration as written — already past the schema gate.
396
+ * @returns {Promise<void>}
397
+ */
398
+ export async function adoptProjectConfig(config: ProjectConfig): Promise<void> {
399
+ if (!requireProjectState()) {
400
+ // No project state is no configuration document either ({@link projectConfigDocument} reads
401
+ // One). The workspace copy is then the only thing there is to keep true.
402
+ setWorkspaceProject(workspace.projectRoot, config);
403
+ return;
404
+ }
405
+ const tab = projectConfigDocument();
406
+ transactDoc(
407
+ tab,
408
+ (t) => replaceContents(t.doc.document as unknown as Record<string, unknown>, config),
409
+ { skipHistory: true },
410
+ );
411
+ tab.doc.dirty = false;
412
+ // Settle a read already in flight before saying what the file holds, or it would resolve after
413
+ // This line with the PREVIOUS bytes and make the next real commit look like a no-op.
414
+ await seedCommitted();
415
+ _committed = serializeProjectConfig(config);
416
+ }