@jxsuite/studio 2.0.1 → 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.
- package/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +21080 -32585
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +7 -0
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +221 -245
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -53
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +30 -1
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +7 -1
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
- package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
- package/dist/chunks/files-j8a1t06k.js +0 -50
- package/dist/chunks/files-j8a1t06k.js.map +0 -9
- package/dist/chunks/git-panel-xtq5z81x.js +0 -28
- package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
- package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
- package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
- package/dist/chunks/settings-modal-17ttr96g.js +0 -29
- package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-0xgs7xrs.js +0 -429
- package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
- package/dist/chunks/studio-4d8hzcz5.js +0 -3427
- package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-jm0z592w.js.map +0 -115
- package/dist/chunks/studio-m2t4mdg5.js +0 -1854
- package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
- package/dist/chunks/studio-n4p11dfy.js +0 -853
- package/dist/chunks/studio-n4p11dfy.js.map +0 -12
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-sjh1wt1a.js +0 -3744
- package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
- package/dist/chunks/studio-v7jkjqng.js.map +0 -46
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-yfcstdzy.js +0 -399
- package/dist/chunks/studio-yfcstdzy.js.map +0 -12
- package/dist/chunks/studio-zp7jncs8.js +0 -469
- package/dist/chunks/studio-zp7jncs8.js.map +0 -14
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /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
|
+
}
|