@jxsuite/studio 5.2.0 → 5.4.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/data/css-meta.json +28 -27
- package/dist/chunks/{cf-account-picker-h4dab9bq.js → cf-account-picker-3f08rry6.js} +21 -18
- package/dist/chunks/{cf-settings-adg74qsk.js → cf-settings-m79r7p5y.js} +4 -4
- package/dist/chunks/{components-5y78e05d.js → components-xm826zjw.js} +3 -3
- package/dist/chunks/{content-source-sgg1sv6n.js → content-source-jt7rbcbc.js} +22 -22
- package/dist/chunks/{convert-to-repeater-mf1cxgfn.js → convert-to-repeater-vg38bq99.js} +22 -22
- package/dist/chunks/{editor-3qhbg51x.js → editor-ddy019sn.js} +2 -2
- package/dist/chunks/entry-commands-64nb2a9a.js +42 -0
- package/dist/chunks/{extension-sections-c6zwzbre.js → extension-sections-r73an5s6.js} +31 -30
- package/dist/chunks/{file-ops-vrpq1jjk.js → file-ops-3xan8mnj.js} +21 -21
- package/dist/chunks/{files-msaf95y6.js → files-egsb0ry8.js} +30 -29
- package/dist/chunks/{format-host-f64fnesp.js → format-host-mym8qnd0.js} +3 -3
- package/dist/chunks/{fs-events-3y6y0nrm.js → fs-events-z2gg8qjt.js} +4 -4
- package/dist/chunks/{git-panel-bv5e22j0.js → git-panel-a05atk6q.js} +20 -20
- package/dist/chunks/{grid-view-1p6hsyjx.css → grid-view-3g1h2re8.css} +956 -139
- package/dist/chunks/{grid-view-paj67nr5.js → grid-view-qaqer9kr.js} +24 -24
- package/dist/chunks/{icons-yy10wk9r.js → icons-drxq9q10.js} +8 -2
- package/dist/chunks/{iframe-host-dh5np8vk.js → iframe-host-psetcv20.js} +11 -11
- package/dist/chunks/{index-n4j7qxyr.js → index-9yjae3hz.js} +4 -4
- package/dist/chunks/{javascript-4abzjcy9.css → javascript-bc9z461d.css} +688 -54
- package/dist/chunks/{javascript-xvrfrpkb.js → javascript-hr5sg57n.js} +2 -2
- package/dist/chunks/{jsonMode-vvmpmk34.css → jsonMode-qqd9nm1t.css} +1120 -303
- package/dist/chunks/{jsonMode-tyx2kj6p.js → jsonMode-zs88v0wr.js} +4 -4
- package/dist/chunks/{jx-validate-j0wxk72w.js → jx-validate-epp2z3s3.js} +2 -2
- package/dist/chunks/layers-panel-83a16ytx.js +41 -0
- package/dist/chunks/{layers-1vcfdbet.js → layers-s6mc01ry.js} +3 -3
- package/dist/chunks/{listbox-6v2ac08j.js → listbox-b7jxnhq1.js} +19 -3
- package/dist/chunks/{media-picker-p49nhqhs.js → media-picker-nhn6rv4w.js} +11 -11
- package/dist/chunks/{menu-qht48vnc.js → menu-8j4qxjrp.js} +4 -4
- package/dist/chunks/{monaco-binding-sw6en4dw.js → monaco-binding-e8d9wzyk.js} +3 -3
- package/dist/chunks/{monaco-buffer-pykwbm92.js → monaco-buffer-jaq1t9zj.js} +2 -2
- package/dist/chunks/{monaco-setup-8vbyqnhr.css → monaco-setup-ey9cjcm3.css} +954 -137
- package/dist/chunks/{monaco-setup-8r62fj6y.js → monaco-setup-gsjdysze.js} +7 -7
- package/dist/chunks/{platform-ts9cg1a4.js → platform-fnchmhy7.js} +5 -3
- package/dist/chunks/publish-panel-ak6hxfma.js +27 -0
- package/dist/chunks/quick-search-c63mkt3b.js +47 -0
- package/dist/chunks/{references-h69xp9zz.js → references-f7bdv3z5.js} +3 -3
- package/dist/chunks/right-panel-t5n8wttg.js +45 -0
- package/dist/chunks/{split-g7nm1rgb.js → split-4cz4b6ef.js} +14 -3
- package/dist/chunks/{studio-sar8g54p.js → studio-01269reb.js} +8 -8
- package/dist/chunks/{studio-rnyf3f8e.js → studio-0a4gncx0.js} +3 -3
- package/dist/chunks/{studio-e1f24eff.js → studio-0d4p4wxj.js} +6778 -2993
- package/dist/chunks/{studio-4wbb9ct0.js → studio-1tejxvba.js} +3006 -1855
- package/dist/chunks/{studio-p6pmwkvh.js → studio-3nprwbd9.js} +147 -28
- package/dist/chunks/{studio-4c041r8y.js → studio-40z39dme.js} +3 -3
- package/dist/chunks/{studio-68fydsrj.js → studio-482eeazk.js} +20 -20
- package/dist/chunks/{studio-y4f9fdge.js → studio-4998spet.js} +10 -9
- package/dist/chunks/{studio-nq5yf5mp.js → studio-557bmn0x.js} +2 -2
- package/dist/chunks/{studio-hdc2jt3z.js → studio-5w26wza5.js} +3 -3
- package/dist/chunks/{studio-6nzaktvy.js → studio-6pwn9j8c.js} +6 -3
- package/dist/chunks/{studio-wnsyffg1.js → studio-6vg0x5fz.js} +3 -2
- package/dist/chunks/{studio-vn5hske5.js → studio-7d3c1m59.js} +12 -5
- package/dist/chunks/{studio-28vs5k2y.js → studio-9vsvz7w7.js} +7 -7
- package/dist/chunks/{studio-t3adrr56.js → studio-9wm0xzpf.js} +19 -19
- package/dist/chunks/{studio-38emantv.js → studio-a5h5j33a.js} +19 -5
- package/dist/chunks/{studio-ympe0n7a.js → studio-ag3z6shb.js} +10 -4
- package/dist/chunks/studio-aj9drheq.js +177 -0
- package/dist/chunks/{studio-vt0tj32j.js → studio-apv9x70c.js} +189 -130
- package/dist/chunks/{studio-c04nzbby.js → studio-b9q3znz8.js} +2 -2
- package/dist/chunks/{studio-2mdbbc76.js → studio-bh47w0cy.js} +9 -10
- package/dist/chunks/{studio-ez11dmdh.js → studio-dgdm6vvt.js} +264 -52
- package/dist/chunks/{studio-5nz00bhh.js → studio-dwdcr2e8.js} +4 -4
- package/dist/chunks/{studio-nqgawfks.js → studio-fbcyz234.js} +146 -139
- package/dist/chunks/{studio-kcgff4r0.js → studio-fgmfksz8.js} +2 -2
- package/dist/chunks/{studio-x72j58vw.js → studio-fqpkpq1t.js} +7 -4
- package/dist/chunks/{studio-15f3kxqe.js → studio-fy320dfc.js} +62 -68
- package/dist/chunks/{studio-zjjde71a.js → studio-gjj4bbfx.js} +2 -2
- package/dist/chunks/{studio-66arbpc2.js → studio-jfhxy8h3.js} +16 -15
- package/dist/chunks/{studio-d0300636.js → studio-ks2zzth2.js} +17 -2
- package/dist/chunks/{studio-c07s5ckd.js → studio-kwewmhhq.js} +4 -4
- package/dist/chunks/{studio-01jeck2y.js → studio-m58xn8at.js} +26 -25
- package/dist/chunks/{studio-mpzwze9x.js → studio-mfkh1q8d.js} +17 -17
- package/dist/chunks/{studio-etvx9s2g.js → studio-mrh0a92f.js} +17 -17
- package/dist/chunks/{studio-qa7fzxan.js → studio-mt79tn56.js} +3 -3
- package/dist/chunks/{studio-hhskq2mr.js → studio-ne593z1j.js} +39 -32
- package/dist/chunks/{studio-h4nvnjvz.js → studio-ptfcxkz5.js} +418 -232
- package/dist/chunks/{studio-4xmjcrg3.js → studio-qxye31h7.js} +7 -7
- package/dist/chunks/{studio-a1pswps3.js → studio-rav5bpmp.js} +81 -59
- package/dist/chunks/{studio-ncn9e189.js → studio-rwmmbrth.js} +6 -6
- package/dist/chunks/{studio-en82c639.js → studio-sceg8ws0.js} +8 -8
- package/dist/chunks/{studio-wjpgxywa.js → studio-sjas5b3a.js} +19 -13
- package/dist/chunks/{studio-4r14yzyy.js → studio-vd67b66d.js} +3 -3
- package/dist/chunks/{studio-14d9tq4d.js → studio-w475cbf9.js} +10 -10
- package/dist/chunks/{studio-ctm7bhx5.js → studio-w7gpcvfj.js} +9 -9
- package/dist/chunks/{studio-9j6sfeba.js → studio-xrbfdxgk.js} +7 -7
- package/dist/chunks/{studio-x10fp4tp.js → studio-y49b6mjv.js} +35 -35
- package/dist/chunks/{studio-5t7ena5z.js → studio-ygvr9e4q.js} +10 -10
- package/dist/chunks/{studio-z2smx5ce.js → studio-yxmmjy2a.js} +9 -6
- package/dist/chunks/{tsMode-jy4m86rv.js → tsMode-ay4c78ne.js} +4 -4
- package/dist/chunks/{tsMode-hnxxb73h.css → tsMode-c72wyz27.css} +954 -137
- package/dist/chunks/{workspace-bnw54cha.js → workspace-b9k2frks.js} +5 -5
- package/dist/chunks/{ws-client-ny4zc51r.js → ws-client-erze4czt.js} +356 -20
- package/dist/codicon.ttf +0 -0
- package/dist/iframe-entry.js +20 -18
- package/dist/studio.css +956 -139
- package/dist/studio.js +1511 -851
- package/dist/workers/editor.worker.js +196 -107
- package/dist/workers/json.worker.js +196 -107
- package/dist/workers/ts.worker.js +196 -107
- package/package.json +18 -17
- package/src/about/about-modal.ts +4 -3
- package/src/browse/library-commands.ts +15 -13
- package/src/browse/library-pane.ts +2 -2
- package/src/canvas/canvas-render.ts +97 -83
- package/src/canvas/canvas-surface.ts +2 -2
- package/src/canvas/canvas-utils.ts +42 -32
- package/src/canvas/diff-toolbar.ts +21 -2
- package/src/canvas/diff-view.ts +30 -6
- package/src/canvas/iframe-entry.ts +2 -2
- package/src/canvas/iframe-host.ts +5 -5
- package/src/canvas/iframe-interaction.ts +7 -6
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-protocol.ts +6 -5
- package/src/canvas/iframe-render.ts +3 -3
- package/src/canvas/popover-state.ts +1 -1
- package/src/canvas/stage-scrollbar.ts +112 -0
- package/src/canvas/surface-registry.ts +9 -2
- package/src/collab/collab-commands.ts +8 -6
- package/src/collab/collab-session.ts +4 -4
- package/src/collab/collab-state.ts +4 -4
- package/src/collab/presence-chips.ts +3 -3
- package/src/commands/app-commands.ts +7 -7
- package/src/commands/budget.ts +17 -16
- package/src/commands/command-args.ts +10 -9
- package/src/commands/context.ts +20 -10
- package/src/commands/defaults.ts +30 -29
- package/src/commands/levels.ts +8 -6
- package/src/commands/live-context.ts +12 -10
- package/src/commands/reference.ts +5 -5
- package/src/commands/registry.ts +2 -2
- package/src/content/draft-state.ts +9 -8
- package/src/content/entry-commands.ts +16 -14
- package/src/content/entry-editor.ts +2 -2
- package/src/content/entry-fields.ts +1 -1
- package/src/editor/context-menu.ts +4 -4
- package/src/editor/convert-to-component.ts +6 -5
- package/src/editor/inline-edit.ts +3 -3
- package/src/editor/shortcuts.ts +88 -20
- package/src/editor/slash-menu.ts +11 -10
- package/src/files/elements.ts +4 -5
- package/src/files/file-ops.ts +1 -1
- package/src/files/files.ts +21 -17
- package/src/files/serialize-document.ts +1 -1
- package/src/format/convert-file.ts +5 -5
- package/src/github/github-auth-status.ts +107 -0
- package/src/github/github-auth.ts +18 -82
- package/src/github/github-publish.ts +7 -6
- package/src/grid/cell-editors.ts +8 -7
- package/src/grid/grid-layout.ts +1 -1
- package/src/grid/grid-open.ts +6 -5
- package/src/grid/grid-panel.ts +13 -12
- package/src/grid/redirects-grid.ts +14 -11
- package/src/grid/redirects.ts +10 -5
- package/src/grid/sources/content-source.ts +10 -9
- package/src/hosting/document.ts +28 -1
- package/src/hosting/stage.ts +15 -4
- package/src/i18n/i18n-commands.ts +9 -7
- package/src/new-project/location-fields.ts +16 -3
- package/src/new-project/new-project-modal.ts +23 -7
- package/src/page-params.ts +6 -6
- package/src/panels/activity-panel.ts +11 -10
- package/src/panels/ai-chat/chat-view.ts +27 -14
- package/src/panels/ai-chat/composer.ts +10 -3
- package/src/panels/ai-panel.ts +87 -29
- package/src/panels/block-action-bar.ts +59 -33
- package/src/panels/bottom-dock.ts +22 -22
- package/src/panels/chat-panel.ts +40 -5
- package/src/panels/data-explorer.ts +9 -9
- package/src/panels/data-grid.ts +1 -1
- package/src/panels/editors.ts +8 -8
- package/src/panels/elements-panel.ts +7 -8
- package/src/panels/empty-state.ts +1 -1
- package/src/panels/events-panel.ts +13 -12
- package/src/panels/formula-workspace.ts +8 -5
- package/src/panels/frontmatter-fields.ts +4 -1
- package/src/panels/frontmatter-panel.ts +18 -18
- package/src/panels/git-panel.ts +19 -13
- package/src/panels/head-panel.ts +9 -10
- package/src/panels/i18n-panel.ts +6 -4
- package/src/panels/imports-panel.ts +1 -1
- package/src/panels/jump-bar.ts +20 -18
- package/src/panels/layers-panel.ts +19 -17
- package/src/panels/left-panel.ts +3 -3
- package/src/panels/navigator-panels.ts +8 -8
- package/src/panels/overlays.ts +1 -1
- package/src/panels/pane-context.ts +56 -28
- package/src/panels/pane-grid.ts +9 -8
- package/src/panels/panel-registry.ts +47 -19
- package/src/panels/problems-panel.ts +11 -12
- package/src/panels/properties-panel.ts +21 -20
- package/src/panels/provenance.ts +3 -3
- package/src/panels/quick-search.ts +15 -11
- package/src/panels/right-panel.ts +4 -3
- package/src/panels/seo-modal.ts +5 -4
- package/src/panels/settings-menu.ts +9 -9
- package/src/panels/settings-pane.ts +3 -3
- package/src/panels/signals-panel.ts +16 -9
- package/src/panels/statement-editor.ts +12 -9
- package/src/panels/style-panel.ts +45 -41
- package/src/panels/stylebook-panel.ts +0 -1
- package/src/panels/tab-strip.ts +26 -23
- package/src/platform-errors.ts +2 -2
- package/src/platform.ts +44 -4
- package/src/platforms/cloud.ts +11 -1
- package/src/platforms/default-platform.ts +141 -4
- package/src/platforms/devserver.ts +23 -3
- package/src/publish/deploy-checklist.ts +11 -10
- package/src/publish/publish-commands.ts +9 -8
- package/src/services/a11y-report.ts +1 -1
- package/src/services/ai-ask.ts +39 -16
- package/src/services/ai-command-tools.ts +28 -14
- package/src/services/ai-import-tools.ts +43 -29
- package/src/services/ai-project-tools.ts +20 -38
- package/src/services/ai-settings.ts +55 -2
- package/src/services/ai-tools.ts +69 -58
- package/src/services/ai-write-report.ts +4 -4
- package/src/services/ai-writes.ts +74 -55
- package/src/services/automation.ts +12 -12
- package/src/services/clock.ts +2 -1
- package/src/services/connection.ts +2 -2
- package/src/services/context-manager.ts +69 -6
- package/src/services/directory-picker.ts +93 -27
- package/src/services/document-assistant.ts +86 -17
- package/src/services/gated-registry.ts +4 -3
- package/src/services/idle.ts +5 -4
- package/src/services/live-surfaces.ts +2 -1
- package/src/services/module-preloads.ts +67 -0
- package/src/services/notify.ts +9 -7
- package/src/services/popover-report.ts +3 -3
- package/src/services/preview-eval.ts +1 -1
- package/src/services/project-adoption.ts +34 -1
- package/src/services/project-path.ts +53 -0
- package/src/services/settings/kernel.ts +13 -2
- package/src/services/tool-executor.ts +135 -30
- package/src/services/tool-outcomes.ts +143 -0
- package/src/settings/contexts-section.ts +8 -8
- package/src/settings/contributed-section.ts +6 -6
- package/src/settings/css-vars-editor.ts +6 -5
- package/src/settings/extension-commands.ts +19 -18
- package/src/settings/extension-sections.ts +7 -7
- package/src/settings/extensions-section.ts +3 -3
- package/src/settings/general-settings.ts +21 -18
- package/src/settings/preferences-accounts.ts +3 -3
- package/src/settings/preferences-dialog.ts +9 -8
- package/src/settings/preferences-sections.ts +1 -1
- package/src/settings/project-sections.ts +2 -2
- package/src/settings/section-registry.ts +7 -6
- package/src/settings/settings-document.ts +41 -43
- package/src/shell/tree.ts +29 -0
- package/src/shell.ts +63 -55
- package/src/site-context.ts +1 -1
- package/src/store.ts +2 -2
- package/src/studio.ts +52 -28
- package/src/style/live-preview.ts +8 -8
- package/src/style/project-styles.ts +8 -9
- package/src/style/token-ref.ts +2 -2
- package/src/surfaces/about.json +6 -2
- package/src/surfaces/add-repo.json +2 -2
- package/src/surfaces/add-repo.ts +2 -2
- package/src/surfaces/ai-chat.json +14 -6
- package/src/surfaces/ai-chat.ts +4 -2
- package/src/surfaces/ai-credentials-form.json +53 -49
- package/src/surfaces/ai-credentials-form.ts +18 -4
- package/src/surfaces/ai-managed-connect.json +4 -4
- package/src/surfaces/block-action-bar.json +4 -4
- package/src/surfaces/block-action-bar.ts +3 -3
- package/src/surfaces/boot-failure.json +228 -0
- package/src/surfaces/boot-failure.ts +156 -0
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/canvas-stage.json +9 -40
- package/src/surfaces/canvas-stage.ts +9 -9
- package/src/surfaces/cf-account-picker.json +11 -8
- package/src/surfaces/commandbar.ts +11 -10
- package/src/surfaces/convert-repeater.ts +3 -2
- package/src/surfaces/dialog.json +7 -1
- package/src/surfaces/dialog.ts +2 -2
- package/src/surfaces/doc-header.json +6 -13
- package/src/surfaces/doc-header.ts +4 -5
- package/src/surfaces/entry-editor.json +1 -1
- package/src/surfaces/entry-editor.ts +2 -1
- package/src/surfaces/expression-editor.json +5 -5
- package/src/surfaces/files-panel.json +4 -3
- package/src/surfaces/files-panel.ts +1 -1
- package/src/surfaces/formula-palette.json +10 -9
- package/src/surfaces/formula-palette.ts +11 -7
- package/src/surfaces/git-panel.json +167 -109
- package/src/surfaces/git-panel.ts +2 -2
- package/src/surfaces/github-auth.json +2 -1
- package/src/surfaces/github-publish.ts +3 -3
- package/src/surfaces/grid-open.json +1 -1
- package/src/surfaces/grid-panel.json +2 -2
- package/src/surfaces/grid-views.json +1 -1
- package/src/surfaces/inspector-dock.json +2 -2
- package/src/surfaces/jump-bar.json +1 -1
- package/src/surfaces/jump-bar.ts +1 -1
- package/src/surfaces/library-pane.ts +2 -1
- package/src/surfaces/logic-panel.json +7 -7
- package/src/surfaces/logic-panel.ts +6 -4
- package/src/surfaces/logic-workspace.json +2 -2
- package/src/surfaces/logic-workspace.ts +2 -2
- package/src/surfaces/media-browser.ts +3 -3
- package/src/surfaces/media-pane.ts +2 -1
- package/src/surfaces/menu.ts +5 -5
- package/src/surfaces/new-project.json +1 -1
- package/src/surfaces/palette.json +8 -7
- package/src/surfaces/pane-context.json +86 -57
- package/src/surfaces/pane-context.ts +2 -1
- package/src/surfaces/pane-grid.json +3 -3
- package/src/surfaces/panel-activity.json +2 -1
- package/src/surfaces/panel-deploy-checklist.json +1 -1
- package/src/surfaces/panel-elements.ts +2 -1
- package/src/surfaces/panel-i18n.ts +2 -1
- package/src/surfaces/panel-outline.json +1 -1
- package/src/surfaces/panel-outline.ts +4 -3
- package/src/surfaces/panel-page.json +2 -2
- package/src/surfaces/panel-page.ts +4 -1
- package/src/surfaces/panel-problems.json +4 -3
- package/src/surfaces/panel-problems.ts +2 -2
- package/src/surfaces/panel-signals.json +23 -8
- package/src/surfaces/panel-signals.ts +5 -1
- package/src/surfaces/panel-stylebook-layers.json +1 -1
- package/src/surfaces/panel-stylebook-layers.ts +2 -2
- package/src/surfaces/preferences.json +21 -8
- package/src/surfaces/preferences.ts +9 -1
- package/src/surfaces/properties-panel.json +4 -4
- package/src/surfaces/properties-panel.ts +2 -2
- package/src/surfaces/publish.json +1 -1
- package/src/surfaces/publish.ts +2 -1
- package/src/surfaces/push-plan.json +4 -3
- package/src/surfaces/rail.json +2 -2
- package/src/surfaces/rail.ts +10 -4
- package/src/surfaces/reference-field.json +1 -1
- package/src/surfaces/schema-form.json +2 -2
- package/src/surfaces/schema-form.ts +1 -1
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +2 -2
- package/src/surfaces/settings-contributed.ts +2 -1
- package/src/surfaces/settings-css-vars.json +4 -4
- package/src/surfaces/settings-deploy.json +4 -4
- package/src/surfaces/settings-deploy.ts +2 -1
- package/src/surfaces/settings-extensions.json +6 -6
- package/src/surfaces/settings-extensions.ts +6 -2
- package/src/surfaces/settings-locales.json +4 -4
- package/src/surfaces/settings-overview.ts +2 -1
- package/src/surfaces/settings-pane.ts +3 -2
- package/src/surfaces/settings-rawjson.ts +1 -1
- package/src/surfaces/slash-menu.ts +4 -4
- package/src/surfaces/statements.json +3 -3
- package/src/surfaces/statusbar.ts +23 -23
- package/src/surfaces/style-panel.json +9 -5
- package/src/surfaces/style-panel.ts +3 -3
- package/src/surfaces/tab-strip.json +2 -2
- package/src/surfaces/target-line.json +1 -1
- package/src/surfaces/target-line.ts +12 -10
- package/src/surfaces/welcome.json +7 -2
- package/src/tabs/doc-op-apply.ts +5 -5
- package/src/tabs/patch-ops.ts +3 -3
- package/src/tabs/project-config.ts +10 -10
- package/src/tabs/selection.ts +1 -1
- package/src/tabs/tab.ts +13 -14
- package/src/tabs/transact.ts +18 -24
- package/src/types.ts +27 -3
- package/src/ui/ai-credentials-form.ts +74 -16
- package/src/ui/ai-managed-connect.ts +68 -19
- package/src/ui/color-selector.ts +1 -1
- package/src/ui/expression-editor.ts +3 -3
- package/src/ui/form-controls.ts +6 -5
- package/src/ui/formula-catalog.ts +4 -4
- package/src/ui/formula-chips.ts +2 -2
- package/src/ui/layers.ts +20 -18
- package/src/ui/panel-resize.ts +8 -28
- package/src/ui/popover-surface.ts +2 -2
- package/src/ui/progress-modal.ts +3 -3
- package/src/ui/regions.ts +14 -9
- package/src/ui/schema-form.ts +10 -9
- package/src/ui/timing.ts +9 -7
- package/src/ui/value-source.ts +4 -4
- package/src/ui/virtual-window.ts +58 -5
- package/src/utils/base64.ts +20 -1
- package/src/utils/canvas-media.ts +1 -1
- package/src/utils/studio-utils.ts +0 -31
- package/src/view.ts +4 -3
- package/src/workspace/pane-derive.ts +14 -13
- package/src/workspace/session.ts +7 -6
- package/src/workspace/workspace.ts +49 -39
- package/styles/canvas.css +1 -27
- package/styles/inspector.css +4 -3
- package/styles/overlays.css +1 -1
- package/styles/tokens.css +17 -1
- package/styles/tokens.json +6 -1
- package/dist/chunks/entry-commands-w9qsxa6q.js +0 -42
- package/dist/chunks/layers-panel-fksbdg4q.js +0 -40
- package/dist/chunks/publish-panel-vz23wwmg.js +0 -27
- package/dist/chunks/quick-search-e9rp74m8.js +0 -46
- package/dist/chunks/right-panel-j97t2yvy.js +0 -45
- package/dist/chunks/studio-727xh0e3.js +0 -76
- package/src/files/json-layout.ts +0 -474
- package/src/services/ai-turn-signal.ts +0 -70
package/src/page-params.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Dynamic route-param helpers for the tab-bar's $params picker.
|
|
4
4
|
*
|
|
5
|
-
* A page like `pages/products/[sku].json` declares its candidate values in a `$paths` block
|
|
6
|
-
* §4.3). At build time the compiler expands those into concrete routes
|
|
7
|
-
* `@jxsuite/compiler`); in the studio the same shapes are resolved live so
|
|
8
|
-
* value to render. The chosen values are substituted into the canvas render
|
|
9
|
-
* (`substitutePreviewParams`), which mirrors what the compiler's context injection
|
|
10
|
-
* matching built page.
|
|
5
|
+
* A page like `pages/products/[sku].json` declares its candidate values in a `$paths` block
|
|
6
|
+
* (site-architecture.md §4.3). At build time the compiler expands those into concrete routes
|
|
7
|
+
* (`resolvePathEntries` in `@jxsuite/compiler`); in the studio the same shapes are resolved live so
|
|
8
|
+
* the author can pick one value to render. The chosen values are substituted into the canvas render
|
|
9
|
+
* document (`substitutePreviewParams`), which mirrors what the compiler's context injection
|
|
10
|
+
* produces for the matching built page.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { documentUrlPattern as routePattern } from "@jxsuite/site/routes";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* Activity — where a long operation lives while it runs, and what it leaves behind (
|
|
3
|
+
* Activity — where a long operation lives while it runs, and what it leaves behind (§16.4).
|
|
4
4
|
*
|
|
5
5
|
* What this replaces: `ui/progress-modal.ts` was **the only surface in Studio with a real error
|
|
6
6
|
* view** — a red headline, the captured log in a `<pre>`, an explicit Close — and it had four call
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
* on its row, which is the affordance a hung install has never had;
|
|
20
20
|
* - And it **fails into Problems** — {@link ActivityHandle.fail} raises a `notify.error` carrying the
|
|
21
21
|
* log as its `detail`, so the failure outlives the run and carries a Retry command. That is
|
|
22
|
-
* §
|
|
22
|
+
* §16.4's promotion of the progress modal's error view into Problems, in one function.
|
|
23
23
|
*
|
|
24
24
|
* **Nothing here blocks.** `showProgressModal` still exists for the four dependency-install sites
|
|
25
|
-
* §
|
|
25
|
+
* §16.4 keeps blocking, and it is now a thin front end over {@link beginActivity} — so even the
|
|
26
26
|
* blocking case leaves an inspectable entry behind, and closing the modal no longer loses it.
|
|
27
27
|
*
|
|
28
28
|
* `services/idle.ts` reads {@link activityIdleBlockers}: an open operation means the app is not
|
|
29
|
-
* settled, which is
|
|
29
|
+
* settled, which is how §16.4 makes running activities a `probe.idle()` source.
|
|
30
30
|
*
|
|
31
31
|
* **The feed itself is a Jx document** (`surfaces/panel-activity.json`, mounted by
|
|
32
32
|
* `surfaces/panel-activity.ts`). What stays here is the record and the vocabulary a row is written
|
|
@@ -154,7 +154,7 @@ export interface ActivityOptions {
|
|
|
154
154
|
* Stop the operation.
|
|
155
155
|
*
|
|
156
156
|
* Its presence is what draws the Cancel button, so an operation that cannot honestly be stopped
|
|
157
|
-
* must not pass one — a Cancel that does nothing is the failure §
|
|
157
|
+
* must not pass one — a Cancel that does nothing is the failure §16 exists to end, restated as a
|
|
158
158
|
* button.
|
|
159
159
|
*/
|
|
160
160
|
cancel?: () => void;
|
|
@@ -176,7 +176,7 @@ export interface ActivityHandle {
|
|
|
176
176
|
/**
|
|
177
177
|
* Finish with a failure — and raise the Problem that outlives it.
|
|
178
178
|
*
|
|
179
|
-
* The log goes into the notification's `detail`, so the persistent, inspectable error view §
|
|
179
|
+
* The log goes into the notification's `detail`, so the persistent, inspectable error view §16.4
|
|
180
180
|
* asks for is the Problems row, not a modal that has to stay open to be read.
|
|
181
181
|
*/
|
|
182
182
|
fail: (message: string, opts?: { action?: string; path?: string }) => void;
|
|
@@ -324,7 +324,7 @@ export function resetActivities(): void {
|
|
|
324
324
|
/**
|
|
325
325
|
* What is still running, as `services/idle.ts` phrases it.
|
|
326
326
|
*
|
|
327
|
-
* §
|
|
327
|
+
* §16.4 makes this a `probe.idle()` condition (§13.5): an app with an operation in flight has not
|
|
328
328
|
* finished reacting, so a screenshot taken now photographs a half-done import. A FINISHED entry is
|
|
329
329
|
* not a blocker — the list stays on screen forever and waiting for it to empty would never settle.
|
|
330
330
|
*/
|
|
@@ -449,8 +449,8 @@ const ACTIVITY_SURFACE: ActivitySurfaceDeps = {
|
|
|
449
449
|
* Two documents, two hosts, and that is the seam rather than a layout: a document CLEARS the host
|
|
450
450
|
* it is given and lit renders BESIDE foreign nodes, so a document and a lit template can never
|
|
451
451
|
* share a container. The checklist belongs to `publish/deploy-checklist.ts` — a deploy is a long
|
|
452
|
-
* operation with a log, which is why
|
|
453
|
-
*
|
|
452
|
+
* operation with a log, which is why it was folded in here rather than given a fifth dock tab — and
|
|
453
|
+
* it sits above the feed because its whole job is to say what is missing BEFORE you begin.
|
|
454
454
|
*
|
|
455
455
|
* **`data-deploy-checklist` and `data-activity-surface` are the markers, and they are attributes
|
|
456
456
|
* rather than classes for two reasons.** Nothing styles them, and a class no stylesheet defines is
|
|
@@ -500,7 +500,8 @@ export function registerActivityPanel(): void {
|
|
|
500
500
|
dock: "bottom",
|
|
501
501
|
icon: "clock-counter-clockwise",
|
|
502
502
|
// No rail button: the Bottom dock's tabs are reached by ⌘J and `view.setBottomTab`, and a
|
|
503
|
-
// Fifth rail slot for a surface with no steady state would spend chrome
|
|
503
|
+
// Fifth rail slot for a surface with no steady state would spend chrome the budget caps
|
|
504
|
+
// (studio-ui-guidelines.md §12.2).
|
|
504
505
|
rail: false,
|
|
505
506
|
badge: () => (runningActivities().length > 0 ? runningActivities().length : null),
|
|
506
507
|
render: () => renderActivityBody(),
|
|
@@ -4,17 +4,19 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Message-row anatomy: user messages render as right-aligned bubbles (attached-context blocks
|
|
6
6
|
* become chips), assistant messages render sanitized markdown plus tool-call chips, tool messages
|
|
7
|
-
* surface failures only
|
|
7
|
+
* surface failures only, the streaming tail renders as plain text with a cursor
|
|
8
8
|
* (markdown parses once on finalize), and chat errors get a danger row with recovery advice and a
|
|
9
9
|
* Retry. **None of that is markup here any more** — `surfaces/ai-chat.json` draws it and this
|
|
10
10
|
* module decides what it says, which is the same split the file always had with a document on the
|
|
11
11
|
* other side of it instead of a lit template.
|
|
12
12
|
*
|
|
13
|
-
* §
|
|
13
|
+
* ai.md §3.2 (the accountable turn) is why three things here are not what they were:
|
|
14
14
|
*
|
|
15
|
-
* - **A chip renders its OUTCOME.** `ToolCallRecord.result
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* - **A chip renders its OUTCOME.** It reads `ToolCallRecord.result`, so a chip that said
|
|
16
|
+
* `update_style: ["children",0]` no longer says exactly as much when the edit was refused as when
|
|
17
|
+
* it landed. The live loop attaches each result as its call finishes (`appendToolResult`), and a
|
|
18
|
+
* restored chat backfills it from the tool message that answered the call
|
|
19
|
+
* (`services/tool-outcomes.ts`).
|
|
18
20
|
* - **A turn renders what it CHANGED.** The changed-files summary comes off the write ledger
|
|
19
21
|
* (`services/ai-writes.ts`), which records whether each change went through a transaction or
|
|
20
22
|
* straight to disk — so the undo caveat is rendered to the human holding ⌘Z instead of being
|
|
@@ -22,8 +24,8 @@
|
|
|
22
24
|
* - **An error offers Retry.** `chatState.retryLast()` has been implemented, exported and called by
|
|
23
25
|
* nobody; the error row is where it belongs.
|
|
24
26
|
*
|
|
25
|
-
* §
|
|
26
|
-
* closures this module received and invoked, so the capabilities existed ONLY as buttons: the
|
|
27
|
+
* ai.md §3.0 is why the three buttons here are not callbacks any more. History, New Chat and Retry
|
|
28
|
+
* were closures this module received and invoked, so the capabilities existed ONLY as buttons: the
|
|
27
29
|
* `Assistant` category held zero records, and nothing could reach them from the palette, a chord,
|
|
28
30
|
* the automation runner or the generated commands sheet. They are {@link projectCommand} now, in
|
|
29
31
|
* the idiom `surfaces/statusbar.ts` established — the record is the definition site, and this file
|
|
@@ -116,6 +118,9 @@ export function formatErrorAdvice(error: string): string {
|
|
|
116
118
|
if (lower.includes("500") || lower.includes("internal")) {
|
|
117
119
|
return "The upstream API returned a server error. Try again in a moment.";
|
|
118
120
|
}
|
|
121
|
+
if (lower.includes("empty reply")) {
|
|
122
|
+
return "Try again, or pick another model: some send back nothing for a request they cannot handle.";
|
|
123
|
+
}
|
|
119
124
|
return "";
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -191,10 +196,9 @@ export function tokenLabel(tokens: number): string {
|
|
|
191
196
|
* The sentence behind the token readout.
|
|
192
197
|
*
|
|
193
198
|
* `services/context-manager.ts` has computed both numbers on every turn since it was written, and
|
|
194
|
-
* `chat-state.ts` has stored them — with NO READER anywhere.
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* why sat in the store.
|
|
199
|
+
* `chat-state.ts` has stored them — with NO READER anywhere. So a conversation was silently
|
|
200
|
+
* trimmed, the assistant forgot what you told it ten turns ago, and the two numbers that would have
|
|
201
|
+
* explained why sat in the store.
|
|
198
202
|
*
|
|
199
203
|
* @param {number} tokens
|
|
200
204
|
* @param {boolean} overBudget
|
|
@@ -289,7 +293,16 @@ export function toolOutcomeText(tc: ToolCallRecord): string {
|
|
|
289
293
|
if (!result) {
|
|
290
294
|
return "";
|
|
291
295
|
}
|
|
292
|
-
|
|
296
|
+
const text = (result.success ? result.summary : result.error) ?? "";
|
|
297
|
+
/* An import's summary is written for the model: its first sentence says what happened ("Imported
|
|
298
|
+
<url> into <root> and opened it", or that it was not opened), and the rest instructs the model
|
|
299
|
+
what to read and ask next. The person reads the first sentence; the rest is not addressed to
|
|
300
|
+
them. The live chip draws the run's own log beside it. */
|
|
301
|
+
if (tc.name === IMPORT_TOOL && result.success) {
|
|
302
|
+
const end = /\.(?:\s|$)/.exec(text);
|
|
303
|
+
return end ? text.slice(0, end.index + 1) : text;
|
|
304
|
+
}
|
|
305
|
+
return text;
|
|
293
306
|
}
|
|
294
307
|
|
|
295
308
|
/** How a question card reaches the store that resolves it, and an import its record. */
|
|
@@ -535,8 +548,8 @@ export function projectRows(opts: MessageListOptions): ChatRowView[] {
|
|
|
535
548
|
continue;
|
|
536
549
|
}
|
|
537
550
|
if (msg.role === "tool") {
|
|
538
|
-
|
|
539
|
-
|
|
551
|
+
/* Show only failed tool results so the user knows why an edit didn't land. Successful tool
|
|
552
|
+
results stay hidden to reduce noise; the chip on the call already states its outcome. */
|
|
540
553
|
const parsed = tryParseToolResult(msg.content);
|
|
541
554
|
if (parsed && !parsed.success) {
|
|
542
555
|
rows.push({
|
|
@@ -40,6 +40,7 @@ import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
|
40
40
|
export interface ComposerOptions {
|
|
41
41
|
/** Receives the full message content (typed text + serialized context). */
|
|
42
42
|
onSend: (text: string) => void;
|
|
43
|
+
/** Whether a turn is in flight: the whole turn, tools included, not only its token stream. */
|
|
43
44
|
isStreaming: () => boolean;
|
|
44
45
|
/**
|
|
45
46
|
* Whether the turn is suspended on a question. The composer becomes the answer field: Enter still
|
|
@@ -72,7 +73,10 @@ export interface Composer {
|
|
|
72
73
|
view: () => ComposerView;
|
|
73
74
|
/** The reader typed. */
|
|
74
75
|
edit: (text: string) => void;
|
|
75
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Send what is typed, if anything is. During a turn, only when a question waits: that send is its
|
|
78
|
+
* answer.
|
|
79
|
+
*/
|
|
76
80
|
send: () => void;
|
|
77
81
|
clear: () => void;
|
|
78
82
|
/** Open the attach menu under the button that was pressed. */
|
|
@@ -239,7 +243,8 @@ export function createComposer(opts: ComposerOptions): Composer {
|
|
|
239
243
|
}
|
|
240
244
|
|
|
241
245
|
function send() {
|
|
242
|
-
|
|
246
|
+
// A send while a question waits is its answer, so a running turn refuses only an ordinary send.
|
|
247
|
+
if (!draft.trim() || (opts.isStreaming() && !(opts.isAwaiting?.() ?? false))) {
|
|
243
248
|
return;
|
|
244
249
|
}
|
|
245
250
|
const text = buildMessageWithContext(draft, chips);
|
|
@@ -290,7 +295,9 @@ export function createComposer(opts: ComposerOptions): Composer {
|
|
|
290
295
|
: "Ask the assistant… (Enter to send)",
|
|
291
296
|
sendDisabled: draft.trim().length === 0,
|
|
292
297
|
sendLabel: awaiting ? "Answer" : "Send",
|
|
293
|
-
|
|
298
|
+
/* Answer, else Stop, else Send. A waiting question outranks Stop because the composer is its
|
|
299
|
+
answer field, and a turn in flight otherwise offers Stop for all of it, tools included. */
|
|
300
|
+
sendState: !awaiting && streaming ? "stop" : "send",
|
|
294
301
|
};
|
|
295
302
|
}
|
|
296
303
|
|
package/src/panels/ai-panel.ts
CHANGED
|
@@ -64,6 +64,7 @@ import type { AiChatSurface, AiChatView } from "../surfaces/ai-chat";
|
|
|
64
64
|
import type { AnyCommand } from "../commands/registry";
|
|
65
65
|
import type { CommandContext } from "../commands/context";
|
|
66
66
|
import type { EffectScope } from "@vue/reactivity";
|
|
67
|
+
import type { Message } from "@jxsuite/ai/chat-state";
|
|
67
68
|
|
|
68
69
|
// ─── State (module-level, persists across tab switches) ─────────────────────
|
|
69
70
|
|
|
@@ -136,11 +137,12 @@ let projectionQueued = false;
|
|
|
136
137
|
* **Coalesced on a microtask, for two reasons that are not about paint.** A turn writes several
|
|
137
138
|
* reactive facts in one tick — the message, the status, the token count — and the transcript
|
|
138
139
|
* projection is O(messages), so running it once per write would rebuild the whole list three times
|
|
139
|
-
* for one event. And the write LEDGER (`services/ai-writes.ts`) is a plain array: `
|
|
140
|
+
* for one event. And the write LEDGER (`services/ai-writes.ts`) is a plain array: `fileTurn` files
|
|
140
141
|
* it immediately after the assistant message lands, so a projection that ran synchronously inside
|
|
141
|
-
* the effect would read the turn's changed-files summary one write too early, every time.
|
|
142
|
-
*
|
|
143
|
-
*
|
|
142
|
+
* the effect would read the turn's changed-files summary one write too early, every time. (When it
|
|
143
|
+
* lands later than that, after a Stop mid-stream, the send re-projects once the turn has settled.)
|
|
144
|
+
* The old frame loop hid both by accident of deferral; this states them. Precedent:
|
|
145
|
+
* `panels/overlays.ts`, studio-ui-guidelines.md §9.3's second scheduler.
|
|
144
146
|
*/
|
|
145
147
|
export function renderAiPanel(): void {
|
|
146
148
|
if (projectionQueued || !surface) {
|
|
@@ -187,8 +189,18 @@ function watchAssistant() {
|
|
|
187
189
|
const last = cs.messages.at(-1);
|
|
188
190
|
void last?.content;
|
|
189
191
|
void last?.toolCalls?.length;
|
|
192
|
+
/* A call's result lands on its request's record once the tool has run, and the chip draws
|
|
193
|
+
it. By then the tail may be an earlier call's `tool` reply rather than the request, so the
|
|
194
|
+
request is found behind the replies, and every one of its records is tracked. */
|
|
195
|
+
for (const tc of latestRequest(cs.messages)?.toolCalls ?? []) {
|
|
196
|
+
void tc.result;
|
|
197
|
+
}
|
|
190
198
|
void cs.status;
|
|
191
199
|
void cs.error;
|
|
200
|
+
// The composer's Send/Stop follows the turn, which outlasts the stream's status.
|
|
201
|
+
void assistant.isTurnActive();
|
|
202
|
+
// A usage frame moves the token count and nothing else this effect reads.
|
|
203
|
+
void cs.tokenCount;
|
|
192
204
|
// The registry is composed AFTER the bootstrap mounts this, and it is a reactive holder —
|
|
193
205
|
// Reading it here is what turns the header's skeleton into its real buttons.
|
|
194
206
|
void activeRegistry();
|
|
@@ -208,6 +220,22 @@ function watchAssistant() {
|
|
|
208
220
|
});
|
|
209
221
|
}
|
|
210
222
|
|
|
223
|
+
/**
|
|
224
|
+
* The assistant message the tool replies at the end of the transcript answer: the one whose chips a
|
|
225
|
+
* running tool's result is about to change.
|
|
226
|
+
*
|
|
227
|
+
* @param {readonly Message[]} messages
|
|
228
|
+
* @returns {Message | undefined}
|
|
229
|
+
*/
|
|
230
|
+
function latestRequest(messages: readonly Message[]): Message | undefined {
|
|
231
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
232
|
+
if (messages[index]!.role !== "tool") {
|
|
233
|
+
return messages[index];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
211
239
|
// ─── Lifecycle ──────────────────────────────────────────────────────────────
|
|
212
240
|
|
|
213
241
|
export function mountAiPanel() {
|
|
@@ -231,14 +259,20 @@ export function mountAiPanel() {
|
|
|
231
259
|
* them is a 400. It travels as the tool result instead, and the question's own card renders it.
|
|
232
260
|
*/
|
|
233
261
|
async function handleAssistantSend(text: string) {
|
|
234
|
-
if (!text.trim()
|
|
262
|
+
if (!text.trim()) {
|
|
235
263
|
return;
|
|
236
264
|
}
|
|
265
|
+
/* Answering comes first: a question is put by a turn that is still running, so a send while one
|
|
266
|
+
waits is its answer, never a second turn. */
|
|
237
267
|
if (answerAsk(text.trim())) {
|
|
238
268
|
surface?.pin();
|
|
239
269
|
renderAiPanel();
|
|
240
270
|
return;
|
|
241
271
|
}
|
|
272
|
+
// One turn per window: a send during a turn, tools included, starts nothing.
|
|
273
|
+
if (isAssistantStreaming()) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
242
276
|
// A send always lands in the chat view, pinned to the newest message.
|
|
243
277
|
view = "chat";
|
|
244
278
|
surface?.pin();
|
|
@@ -248,11 +282,18 @@ async function handleAssistantSend(text: string) {
|
|
|
248
282
|
} catch {
|
|
249
283
|
// Synchronous failure (e.g. network unreachable) — the DocumentAssistant's
|
|
250
284
|
// Own try/catch calls chatState.setError(), which the watcher renders.
|
|
285
|
+
} finally {
|
|
286
|
+
/* The turn's changes are filed in the loop's `finally`, and the ledger is not reactive. It is
|
|
287
|
+
usually filed in the same job as the turn's last reactive write, but not after a Stop
|
|
288
|
+
mid-stream: that write (`cancelStream`) lands microtasks before the aborted stream winds
|
|
289
|
+
down, so the coalesced projection has already drawn the reply without its summary. One
|
|
290
|
+
projection once the turn has settled is the one that is guaranteed to see it. */
|
|
291
|
+
renderAiPanel();
|
|
251
292
|
}
|
|
252
293
|
}
|
|
253
294
|
|
|
254
295
|
/**
|
|
255
|
-
* Re-send the last user message — §
|
|
296
|
+
* Re-send the last user message — ai.md §3.0's Retry.
|
|
256
297
|
*
|
|
257
298
|
* `chatState.retryLast()` pops the failed assistant turn AND the user message that caused it, on
|
|
258
299
|
* the contract that the caller re-sends. It has been exported with zero callers since it was
|
|
@@ -272,7 +313,7 @@ async function handleRetry(): Promise<void> {
|
|
|
272
313
|
}
|
|
273
314
|
|
|
274
315
|
/**
|
|
275
|
-
* Undo everything one assistant turn changed — §
|
|
316
|
+
* Undo everything one assistant turn changed — ai.md §3.2's "Restore to here".
|
|
276
317
|
*
|
|
277
318
|
* The loop opens one batch per turn per document, so undoing the turn is undoing that batch. The
|
|
278
319
|
* button is offered by the projection only when every recorded change was transactional; this guard
|
|
@@ -314,8 +355,19 @@ export function handleRestore(messageId: string): void {
|
|
|
314
355
|
* project brief). Delegates to the same send path as the composer. Safe to call right after the
|
|
315
356
|
* Assistant tab renders — the reactive watcher projects chat-state into the panel whenever it
|
|
316
357
|
* mounts.
|
|
358
|
+
*
|
|
359
|
+
* **A seed waits for the window's turn, and is never refused.** One window runs one turn, and a
|
|
360
|
+
* turn outlives the call that ended it: New Chat stops the running one, but its loop unwinds
|
|
361
|
+
* afterwards, and a project switch does not stop it at all. A seed sent in that window was refused
|
|
362
|
+
* and lost without a word, taking the New Project hand-off with it. Waiting also keeps a seed from
|
|
363
|
+
* being taken as the answer to a question the old turn still had open.
|
|
317
364
|
*/
|
|
318
365
|
export async function seedAssistantPrompt(text: string): Promise<void> {
|
|
366
|
+
/* One wait is enough: the turn's end settles in its loop's `finally`, and this resumes on the next
|
|
367
|
+
microtask, before any event could start another turn. */
|
|
368
|
+
if (assistant.isTurnActive()) {
|
|
369
|
+
await assistant.whenTurnEnds();
|
|
370
|
+
}
|
|
319
371
|
await handleAssistantSend(text);
|
|
320
372
|
}
|
|
321
373
|
|
|
@@ -461,15 +513,20 @@ export function isAssistantWaiting(): boolean {
|
|
|
461
513
|
* Whether a turn is in flight — the probe `commands/live-context.ts` declares as `aiStreaming` and
|
|
462
514
|
* projects onto `ctx.ai.streaming`.
|
|
463
515
|
*
|
|
516
|
+
* The whole turn, not the token stream. The chat's `status` reads idle while a round's tools run,
|
|
517
|
+
* while a question waits and through a minutes-long import, so reading it here left Stop refused
|
|
518
|
+
* and Send offered in the middle of a turn, and a second send could start a second turn beside the
|
|
519
|
+
* first. The assistant's own turn fact is true from an accepted send until its loop ends.
|
|
520
|
+
*
|
|
464
521
|
* That source was declared optional with the note "there is nothing to read yet; the caller passes
|
|
465
522
|
* a probe when one exists", and no caller ever did — so `ctx.ai.streaming` read `false` forever and
|
|
466
|
-
* `assistant.stop` would have been permanently refused. Reading the reactive
|
|
467
|
-
* what makes the fact LIVE: `createLiveContext` builds a fresh record per predicate
|
|
468
|
-
* a surface projecting from an effect tracks
|
|
469
|
-
* ends.
|
|
523
|
+
* `assistant.stop` would have been permanently refused. Reading the assistant's reactive turn flag
|
|
524
|
+
* here is what makes the fact LIVE: `createLiveContext` builds a fresh record per predicate
|
|
525
|
+
* evaluation, so a surface projecting from an effect tracks the flag and re-projects when a turn
|
|
526
|
+
* starts or ends.
|
|
470
527
|
*/
|
|
471
528
|
export function isAssistantStreaming(): boolean {
|
|
472
|
-
return assistant.
|
|
529
|
+
return assistant.isTurnActive();
|
|
473
530
|
}
|
|
474
531
|
|
|
475
532
|
function stop() {
|
|
@@ -595,25 +652,24 @@ function projectPanel(): AiChatView {
|
|
|
595
652
|
};
|
|
596
653
|
}
|
|
597
654
|
|
|
598
|
-
// ─── The `Assistant:` command family (§
|
|
655
|
+
// ─── The `Assistant:` command family (ai.md §3.0) ───────────────────────────
|
|
599
656
|
|
|
600
657
|
/**
|
|
601
658
|
* Six records, beside the chat session they write.
|
|
602
659
|
*
|
|
603
|
-
*
|
|
604
|
-
* `Assistant` category — declared in `commands/levels.ts` since the taxonomy landed — held
|
|
605
|
-
* records. Every capability below already existed and every one of them existed ONLY as a
|
|
606
|
-
* this panel: not in the palette, not bindable, not reachable by `__jxAutomation` or by
|
|
607
|
-
* absent from the generated commands and shortcuts sheets. A capability that one surface
|
|
608
|
-
* and the registry cannot is the second definition site inverted.
|
|
660
|
+
* The chat column's demotion into an Inspector tab was paid for with a command family (ai.md §3.0),
|
|
661
|
+
* and the `Assistant` category — declared in `commands/levels.ts` since the taxonomy landed — held
|
|
662
|
+
* ZERO records. Every capability below already existed and every one of them existed ONLY as a
|
|
663
|
+
* button in this panel: not in the palette, not bindable, not reachable by `__jxAutomation` or by
|
|
664
|
+
* name, and absent from the generated commands and shortcuts sheets. A capability that one surface
|
|
665
|
+
* can reach and the registry cannot is the second definition site inverted.
|
|
609
666
|
*
|
|
610
|
-
* **All six are `level: "application"`, by
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
* only.
|
|
667
|
+
* **All six are `level: "application"`, by §13.2 — a record is filed by the level of the state it
|
|
668
|
+
* WRITES, not the state it reads.** The chat session is application state: it outlives the open
|
|
669
|
+
* document, survives project close, and `assistant.attachSelection` is the case that proves the
|
|
670
|
+
* rule — it READS the canvas selection and writes a chip into the composer, so it is application,
|
|
671
|
+
* not selection, however selection-ish it looks. That is also why it may declare `menus:
|
|
672
|
+
* ["palette"]` at all: `blockbar` and `context/element` admit selection-level records only.
|
|
617
673
|
*
|
|
618
674
|
* **No `aiTool` on any of them.** The assistant projecting "start a new chat" into its own tool
|
|
619
675
|
* list would let a turn end its own conversation; the tier tables in `services/ai-tools.ts` gate
|
|
@@ -710,9 +766,11 @@ export function assistantCommands(): AnyCommand[] {
|
|
|
710
766
|
menus: ["palette"],
|
|
711
767
|
group: "2_turn",
|
|
712
768
|
requires: "a turn in flight",
|
|
713
|
-
/*
|
|
714
|
-
`
|
|
715
|
-
|
|
769
|
+
/* `streaming` covers the whole turn, a waiting question included: a turn suspended on
|
|
770
|
+
`ask_user` moves no tokens, and it is precisely the turn a reader who does not want to
|
|
771
|
+
answer needs to end. A question is only ever put inside a turn, so `waiting` adds nothing
|
|
772
|
+
here; it stays in the union so a question could still be stopped if one were ever raised
|
|
773
|
+
without a turn. */
|
|
716
774
|
enablement: (ctx: CommandContext) => ctx.ai.streaming || ctx.ai.waiting,
|
|
717
775
|
run: stop,
|
|
718
776
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Block action bar — the floating toolbar above the selected element.
|
|
4
4
|
*
|
|
5
|
-
* The bar is a RENDERING of the command registry (
|
|
5
|
+
* The bar is a RENDERING of the command registry (§4.4, §13): its verb cluster is
|
|
6
6
|
* `registry.forPlacement("blockbar")`, sliced at {@link BLOCKBAR_MAX_ITEMS} with the remainder
|
|
7
7
|
* behind a `⋮` overflow menu. Every button's accessible name is its record's `title` and its
|
|
8
8
|
* tooltip carries `keymap.formatBinding(id)`, so no action is named twice.
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* whether each can act, where the bar belongs against the selection rect, when it steps aside, and
|
|
20
20
|
* what a press does. The toolbar role, the roving caret and the ←/→/Home/End contract are
|
|
21
21
|
* `jx-action-group`'s, so the hand-written `[data-toolbar-item]` ring is gone with the template
|
|
22
|
-
* that needed it; the `⋮` menu is the kit menu every other Studio surface opens
|
|
23
|
-
* is no second list of actions.
|
|
22
|
+
* that needed it; the `⋮` menu is the kit menu every other Studio surface opens
|
|
23
|
+
* (studio-ui-guidelines.md §12.5), so there is no second list of actions.
|
|
24
24
|
*
|
|
25
25
|
* This module is also the single definition site for the structural selection verbs — move
|
|
26
26
|
* up/down/in/out and the component pair — because their implementations live here.
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
} from "../store";
|
|
50
50
|
import { activeTab } from "../workspace/workspace";
|
|
51
51
|
import { activeCanvasSurface, stageContaining } from "../canvas/canvas-surface";
|
|
52
|
+
import { panelOfSurface } from "../canvas/canvas-helpers";
|
|
52
53
|
import { primarySelection, structuralBatch } from "../tabs/selection";
|
|
53
54
|
import {
|
|
54
55
|
mutateDuplicateNodes,
|
|
@@ -207,10 +208,13 @@ function repositionBlockActionBar(): void {
|
|
|
207
208
|
});
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
/** The bar's own height plus its 4px stand-off: the room it needs ABOVE an anchor to stand there. */
|
|
212
|
+
const BAR_CLEARANCE = 38;
|
|
213
|
+
|
|
210
214
|
/**
|
|
211
|
-
* The bar's position for `anchor` (flipping below the element
|
|
212
|
-
* anchor's vertical extent has left the canvas area — the popover layer has no
|
|
213
|
-
* clamped bar would float detached over the app toolbar / panel headers.
|
|
215
|
+
* The bar's position for `anchor` (flipping below the element when it cannot stand above it), or
|
|
216
|
+
* null when the anchor's vertical extent has left the canvas area — the popover layer has no
|
|
217
|
+
* clipping, so a clamped bar would float detached over the app toolbar / panel headers.
|
|
214
218
|
*
|
|
215
219
|
* @param {{ left: number; top: number; height: number }} anchor
|
|
216
220
|
*/
|
|
@@ -224,17 +228,39 @@ function barPosition(anchor: {
|
|
|
224
228
|
stage — and the pane is the FOCUSED one, because that is where the caret is. This asked
|
|
225
229
|
"the stage showing the active tab", which was the same answer only while a tab could be on
|
|
226
230
|
screen in one place; with a document displayed in two panes it picked whichever came first in
|
|
227
|
-
the grid, and clipped the bar against a stage the author is not typing in.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
the grid, and clipped the bar against a stage the author is not typing in.
|
|
232
|
+
…and against the box that SCROLLS, where the stage has one. Edit docks the Document Header
|
|
233
|
+
card above its scroller, inside the same stage cell, so a node scrolled up under the band is
|
|
234
|
+
still inside the stage while nobody can see it — and the bar would float over the card,
|
|
235
|
+
pointing at a node the card is covering. Everywhere else there is no scroller and the stage is
|
|
236
|
+
the viewport, as it always was. */
|
|
237
|
+
const surface = activeCanvasSurface();
|
|
238
|
+
const viewport = panelOfSurface(surface)?.scrollContainer ?? surface.wrap;
|
|
239
|
+
const box = viewport ? rectOf(viewport) : null;
|
|
240
|
+
if (box && (anchor.top + anchor.height < box.top || anchor.top > box.bottom)) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
/* ABOVE the anchor where the bar fits above it INSIDE that viewport, and BELOW it where it does
|
|
244
|
+
not. The flip used to be decided against a flat 80 in WINDOW coordinates, the app's own top
|
|
245
|
+
chrome, which is the same answer only while the viewport starts near the top of the window.
|
|
246
|
+
Edit's scroller starts under a band, so an anchor whose top had scrolled under the card while
|
|
247
|
+
its bottom was still on screen put the bar ON the card — over the fields it covers, taking
|
|
248
|
+
their clicks. Flipped is better than hidden: the element is visible, so its bar should be, and
|
|
249
|
+
past the clip above the anchor's bottom edge is inside the viewport, so the flipped bar is too.
|
|
250
|
+
The fallback is that same 80px of chrome, for a stage no pass has measured yet. */
|
|
251
|
+
const ceiling = box ? box.top : 80 - BAR_CLEARANCE;
|
|
252
|
+
const above = anchor.top - BAR_CLEARANCE;
|
|
253
|
+
if (above >= ceiling) {
|
|
254
|
+
return { left: anchor.left, top: above };
|
|
234
255
|
}
|
|
256
|
+
/* Below it, and kept INSIDE the viewport: an element taller than what is left of the scroller has
|
|
257
|
+
its bottom edge off screen, and the bar would follow it there — over the status bar, or over
|
|
258
|
+
whatever the pane below is showing. Clamped, it stands on that element's last visible strip,
|
|
259
|
+
still pointing at it and still off the card. */
|
|
260
|
+
const below = anchor.top + anchor.height + 4;
|
|
235
261
|
return {
|
|
236
262
|
left: anchor.left,
|
|
237
|
-
top:
|
|
263
|
+
top: box ? Math.max(box.top, Math.min(below, box.bottom - BAR_CLEARANCE)) : below,
|
|
238
264
|
};
|
|
239
265
|
}
|
|
240
266
|
|
|
@@ -276,16 +302,16 @@ function clampBarToWindow(bar: HTMLElement): void {
|
|
|
276
302
|
* `formatBold` because Jx owns its markup. So ⌘B in the canvas did nothing at all, in an app whose
|
|
277
303
|
* toolbar advertised it.
|
|
278
304
|
*
|
|
279
|
-
* They are the case
|
|
280
|
-
* it says: `level: "selection"` — a range inside the selected node is still the
|
|
281
|
-
* fifth `range` level would demand a fifth region — with `keyScope: "caret"`,
|
|
282
|
-
* the chord live only where a caret is. They were, until this change, the only
|
|
283
|
-
* with a chord and no record.
|
|
305
|
+
* They are the case that justifies the record's two fields (specs/studio.md §13.2–§13.3), so they
|
|
306
|
+
* are written the way it says: `level: "selection"` — a range inside the selected node is still the
|
|
307
|
+
* selection, and a fifth `range` level would demand a fifth region — with `keyScope: "caret"`,
|
|
308
|
+
* which is what makes the chord live only where a caret is. They were, until this change, the only
|
|
309
|
+
* capability in Studio with a chord and no record.
|
|
284
310
|
*
|
|
285
311
|
* **The set is the schema's, the verbs are the registry's.** `data/elements-meta.json` says which
|
|
286
312
|
* of the eight a given tag accepts (`$inlineActions`), so the bar draws four on an `<h1>` and eight
|
|
287
313
|
* on a `<p>`; what each one is CALLED, which chord it holds and what it does are on the record.
|
|
288
|
-
* That is the same division
|
|
314
|
+
* That is the same division §6.6 makes for value sources — caps derive from the schema, behaviour
|
|
289
315
|
* does not.
|
|
290
316
|
*
|
|
291
317
|
* `when` is {@link CommandContext.caret.inCanvas} and not `caret.active`: the caret stack is live
|
|
@@ -654,9 +680,9 @@ const hasTarget = (ctx: CommandContext) => ctx.selection.count > 0;
|
|
|
654
680
|
* (Duplicate, from `commands/defaults.ts`) and `9_danger` (Delete, likewise), which is the order
|
|
655
681
|
* the bar and the Outline rows both render in.
|
|
656
682
|
*
|
|
657
|
-
* No `keybinding` is claimed here on purpose. The chord table
|
|
658
|
-
*
|
|
659
|
-
* buttons still print the chords of the records that DO carry them.
|
|
683
|
+
* No `keybinding` is claimed here on purpose. The chord table belongs to `editor/shortcuts.ts`'s
|
|
684
|
+
* scope-stack dispatcher (§13.3); claiming chords from a panel would decide its contents by
|
|
685
|
+
* accident. The buttons still print the chords of the records that DO carry them.
|
|
660
686
|
*/
|
|
661
687
|
export function registerSelectionCommands(
|
|
662
688
|
registry: CommandRegistry,
|
|
@@ -828,7 +854,7 @@ export function selectionCommandRegistry(): CommandRegistry {
|
|
|
828
854
|
return registry;
|
|
829
855
|
}
|
|
830
856
|
|
|
831
|
-
/** How many verb buttons
|
|
857
|
+
/** How many verb buttons render before the rest fold into `⋮` (studio-ui-guidelines.md §12.1). */
|
|
832
858
|
export const BLOCKBAR_MAX_ITEMS = 5;
|
|
833
859
|
|
|
834
860
|
/**
|
|
@@ -996,10 +1022,10 @@ export function dismissBlockBarOverflow(): void {
|
|
|
996
1022
|
* Show the `⋮` menu under `anchor`. Rows carry the same names, chords and refusals as the buttons.
|
|
997
1023
|
*
|
|
998
1024
|
* Shared by the block action bar and the Outline rows, and it is the KIT menu
|
|
999
|
-
* (`surfaces/menu.json`, §12.5) rather than a list of this surface's own:
|
|
1000
|
-
* caret, one typeahead, one Escape. `target` (the Outline row's node) is
|
|
1001
|
-
* re-applied when a row is chosen, because a row action acts on the row's node
|
|
1002
|
-
* is not the selected one.
|
|
1025
|
+
* (`surfaces/menu.json`, studio-ui-guidelines.md §12.5) rather than a list of this surface's own:
|
|
1026
|
+
* one popover, one roving caret, one typeahead, one Escape. `target` (the Outline row's node) is
|
|
1027
|
+
* captured per row and re-applied when a row is chosen, because a row action acts on the row's node
|
|
1028
|
+
* and the hovered row is not the selected one.
|
|
1003
1029
|
*/
|
|
1004
1030
|
export function showCommandOverflow(
|
|
1005
1031
|
anchor: HTMLElement,
|
|
@@ -1192,10 +1218,10 @@ export function isLinkPopoverOpen(): boolean {
|
|
|
1192
1218
|
* snapshot; Apply/Remove post `applyFormat` link intents the iframe applies.
|
|
1193
1219
|
*
|
|
1194
1220
|
* By RECORD ID, not by rendered text. This queried `sp-action-button[title^="Link"]`, which is the
|
|
1195
|
-
* addressing
|
|
1196
|
-
* (it now reads "Link… (⌘K)", and on Windows it reads
|
|
1197
|
-
* the app accepts, and the button is one the surface
|
|
1198
|
-
* module re-finds.
|
|
1221
|
+
* addressing the shot contract's R1 (`scripts/screenshots/README.md`) bans in the screenshot
|
|
1222
|
+
* manifest — a match on a title the app DERIVES (it now reads "Link… (⌘K)", and on Windows it reads
|
|
1223
|
+
* something else again). The id is the input the app accepts, and the button is one the surface
|
|
1224
|
+
* ANNOUNCED as it drew it rather than one this module re-finds.
|
|
1199
1225
|
*/
|
|
1200
1226
|
export function openLinkPopoverFromShortcut(): void {
|
|
1201
1227
|
const surface = _surface;
|
|
@@ -1413,7 +1439,7 @@ function projectBar(): BlockBarView | null {
|
|
|
1413
1439
|
(editingProp ? ` · ${editingProp}` : "");
|
|
1414
1440
|
// The handle is chrome, not a verb, so it renders on every selection; only a node that actually
|
|
1415
1441
|
// Sits at a child index can be dragged, and at the root it is a disabled affordance rather than a
|
|
1416
|
-
// Missing one (§8.6: ONE shape).
|
|
1442
|
+
// Missing one (studio-ui-guidelines.md §8.6: ONE shape).
|
|
1417
1443
|
const canDrag = structuralTarget(selection) !== null;
|
|
1418
1444
|
|
|
1419
1445
|
return {
|