@jxsuite/studio 10.4.0 → 10.6.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/locales/en/elements.json +434 -0
- package/data/webdata.json +116 -139
- package/dist/chunks/2020-rqm7qrje.js +4 -0
- package/dist/chunks/adapter-cyy8vbcx.js +4 -0
- package/dist/chunks/add-new-flow-8cgtejv2.js +4 -0
- package/dist/chunks/{cf-account-picker-xb8vvt2h.js → cf-account-picker-v3qd2dhw.js} +3 -3
- package/dist/chunks/cf-settings-1fnw874z.js +4 -0
- package/dist/chunks/{color-area-h8dbasp1.js → color-area-frd9y9q6.js} +2 -2
- package/dist/chunks/color-field-rebpbe33.js +4 -0
- package/dist/chunks/{color-slider-nz2mrzky.js → color-slider-6bzmk3s7.js} +2 -2
- package/dist/chunks/color-t2bnnj8y.js +4 -0
- package/dist/chunks/{combobox-6hs00996.js → combobox-c49x7gf1.js} +3 -3
- package/dist/chunks/components-y8yhdd7d.js +4 -0
- package/dist/chunks/content-source-9e7qvmsf.js +4 -0
- package/dist/chunks/convert-to-repeater-pd2w4z21.js +4 -0
- package/dist/chunks/editor-mb9jzdrw.js +4 -0
- package/dist/chunks/entry-commands-at0wnx3f.js +4 -0
- package/dist/chunks/extension-sections-4z9qq0gh.js +4 -0
- package/dist/chunks/file-ops-dtdvjmza.js +4 -0
- package/dist/chunks/files-8pf70854.js +4 -0
- package/dist/chunks/format-host-fd3m2y2a.js +4 -0
- package/dist/chunks/fs-events-hrk29vcv.js +4 -0
- package/dist/chunks/grid-open-bh74v82z.js +4 -0
- package/dist/chunks/{grid-view-2f03wcgw.js → grid-view-a51mgzmq.js} +17 -17
- package/dist/chunks/{icons-gb967qc8.js → icons-qp8fn1k8.js} +2 -2
- package/dist/chunks/{iframe-entry-btck0e9s.js → iframe-entry-mpwe5pwk.js} +4 -4
- package/dist/chunks/{iframe-entry-2x9bn5ng.js → iframe-entry-msd43x9h.js} +4 -4
- package/dist/chunks/iframe-entry-rt8jz5t8.js +5 -0
- package/dist/chunks/{iframe-entry-b5qgggyp.js → iframe-entry-v40cr813.js} +4 -4
- package/dist/chunks/iframe-host-q0s0wwy3.js +4 -0
- package/dist/chunks/{image-bake-4afr4y6a.js → image-bake-q9ajdjsj.js} +3 -3
- package/dist/chunks/{image-editor-x7t8jbjn.js → image-editor-ke9std9b.js} +3 -3
- package/dist/chunks/index-57ang7ma.js +4 -0
- package/dist/chunks/index-eytr7av4.js +17 -0
- package/dist/chunks/{index-yjrfeks8.js → index-x495reff.js} +3 -3
- package/dist/chunks/{javascript-hy2mws8v.js → javascript-qe34bvaz.js} +3 -3
- package/dist/chunks/jsonMode-m8rseh31.js +13 -0
- package/dist/chunks/jx-validate-bbd1mary.js +4 -0
- package/dist/chunks/layers-panel-wcjtdqsa.js +4 -0
- package/dist/chunks/layers-yscpys6q.js +4 -0
- package/dist/chunks/{listbox-7gka1h86.js → listbox-tktzq5xj.js} +2 -2
- package/dist/chunks/lit-html-qm5wbhqz.js +4 -0
- package/dist/chunks/media-library-2hfff88g.js +4 -0
- package/dist/chunks/media-open-4pb05cne.js +4 -0
- package/dist/chunks/media-picker-bzktmmwr.js +4 -0
- package/dist/chunks/menu-xc3cbgsd.js +4 -0
- package/dist/chunks/{monaco-binding-a51py33c.js → monaco-binding-7t38arh9.js} +3 -3
- package/dist/chunks/monaco-buffer-3vz94c9f.js +4 -0
- package/dist/chunks/monaco-setup-fstdew02.js +4 -0
- package/dist/chunks/notify-gbdcckrh.js +4 -0
- package/dist/chunks/parse-fpdzgk4c.js +4 -0
- package/dist/chunks/platform-9g72gdqr.js +4 -0
- package/dist/chunks/popover-cnmsav6b.js +4 -0
- package/dist/chunks/publish-panel-91x1cb5d.js +4 -0
- package/dist/chunks/publish-quick-e2dmf7eg.js +4 -0
- package/dist/chunks/publish-workspace-1x8mnzrj.js +4 -0
- package/dist/chunks/quick-search-2m4y6p1x.js +4 -0
- package/dist/chunks/references-yg1g9rwx.js +4 -0
- package/dist/chunks/right-panel-7mfyhzrk.js +4 -0
- package/dist/chunks/source-control-rrc4jgp5.js +4 -0
- package/dist/chunks/{split-m5rwn31z.js → split-d15yencd.js} +2 -2
- package/dist/chunks/studio-0jhhznxy.js +9 -0
- package/dist/chunks/studio-0nb57pjg.js +7 -0
- package/dist/chunks/{studio-s24mhq0z.js → studio-0wa4wv4s.js} +4 -4
- package/dist/chunks/studio-0z8kp4xk.js +5 -0
- package/dist/chunks/{studio-g0hxtcga.js → studio-18gc5t3v.js} +4 -4
- package/dist/chunks/{studio-4fnb5648.js → studio-1b79rpcb.js} +4 -4
- package/dist/chunks/studio-211q5j7m.js +4 -0
- package/dist/chunks/studio-213pyfxh.js +16 -0
- package/dist/chunks/studio-2b1smjvp.js +5 -0
- package/dist/chunks/{studio-nwf0c32p.js → studio-2v6tc9jp.js} +4 -4
- package/dist/chunks/studio-30j0wz99.js +5 -0
- package/dist/chunks/studio-3kmqhwtt.js +5 -0
- package/dist/chunks/studio-44drsmhw.js +5 -0
- package/dist/chunks/{studio-2pk7kc7z.js → studio-495b6f2r.js} +4 -4
- package/dist/chunks/{studio-jma2q8r9.js → studio-4gthb2fd.js} +4 -4
- package/dist/chunks/{studio-0gvvqj3h.js → studio-4xadhxj1.js} +4 -4
- package/dist/chunks/{studio-nvcn2ykc.js → studio-52mzbxqm.js} +4 -4
- package/dist/chunks/{studio-v7a7yb5w.js → studio-56mmnsw8.js} +7 -7
- package/dist/chunks/studio-59hz8f4r.js +5 -0
- package/dist/chunks/{studio-sce30r7b.js → studio-5k9mfafh.js} +3 -3
- package/dist/chunks/{studio-rr00ex23.js → studio-5qez462c.js} +6 -6
- package/dist/chunks/studio-6tnpg0vx.js +5 -0
- package/dist/chunks/studio-6w8mt734.js +6 -0
- package/dist/chunks/studio-7hm04x5z.js +5 -0
- package/dist/chunks/studio-8atmfjjm.js +7 -0
- package/dist/chunks/{studio-wmjmsw0p.js → studio-8n99z71s.js} +4 -4
- package/dist/chunks/studio-8vmad6x2.js +5 -0
- package/dist/chunks/studio-93p5k4r4.js +5 -0
- package/dist/chunks/{studio-2x972v58.js → studio-9gb0m81w.js} +4 -4
- package/dist/chunks/studio-a4ymg4vd.js +5 -0
- package/dist/chunks/studio-anc8067x.js +5 -0
- package/dist/chunks/{studio-2e4hry72.js → studio-dbdt67kr.js} +5 -5
- package/dist/chunks/studio-dbex091t.js +5 -0
- package/dist/chunks/{studio-amaz545p.js → studio-dj8ctxey.js} +4 -4
- package/dist/chunks/{studio-k2evngrj.js → studio-ed9bz68j.js} +5 -5
- package/dist/chunks/{studio-4bgvvzhv.js → studio-fe2d1fp5.js} +4 -4
- package/dist/chunks/{studio-45mj4jqe.js → studio-fgp4cyy3.js} +4 -4
- package/dist/chunks/studio-ft706q02.js +5 -0
- package/dist/chunks/studio-g79s1dyg.js +6 -0
- package/dist/chunks/{studio-pj216fmn.js → studio-gahswxp4.js} +4 -4
- package/dist/chunks/studio-gbqc12bk.js +5 -0
- package/dist/chunks/studio-gxphbetb.js +6 -0
- package/dist/chunks/studio-hdf01j7q.js +7 -0
- package/dist/chunks/studio-hf259xzd.js +48 -0
- package/dist/chunks/studio-jbva4wxw.js +5 -0
- package/dist/chunks/studio-jj9gf1qc.js +5 -0
- package/dist/chunks/studio-jsjg3mjv.js +5 -0
- package/dist/chunks/studio-jtvb8hd7.js +5 -0
- package/dist/chunks/{studio-g9brbewz.js → studio-kp4vzrct.js} +4 -4
- package/dist/chunks/studio-kpx02gaa.js +7 -0
- package/dist/chunks/{studio-3na1r48j.js → studio-kv1728ex.js} +8 -8
- package/dist/chunks/studio-m25ry0mf.js +5 -0
- package/dist/chunks/studio-mcbwmkyh.js +5 -0
- package/dist/chunks/studio-meajkr51.js +5 -0
- package/dist/chunks/studio-mkjrjpr2.js +6 -0
- package/dist/chunks/{studio-eqcddvc2.js → studio-mr084886.js} +201 -201
- package/dist/chunks/studio-mrb10hv3.js +5 -0
- package/dist/chunks/{studio-0939t1q1.js → studio-nhpg405j.js} +4 -4
- package/dist/chunks/studio-nsec0hxm.js +64 -0
- package/dist/chunks/{studio-xx3r3sb0.js → studio-nv0mh0p5.js} +4 -4
- package/dist/chunks/studio-pafmb06w.js +5 -0
- package/dist/chunks/{studio-pm17wdc4.js → studio-pgftd79b.js} +4 -4
- package/dist/chunks/{studio-4zd6an2b.js → studio-pk961xgz.js} +4 -4
- package/dist/chunks/studio-pzbr7g05.js +5 -0
- package/dist/chunks/studio-qcc5hsw2.js +10 -0
- package/dist/chunks/studio-qfq58c8n.js +5 -0
- package/dist/chunks/studio-qvb2jr83.js +5 -0
- package/dist/chunks/studio-r85zw6ay.js +5 -0
- package/dist/chunks/studio-s0kwce5w.js +9 -0
- package/dist/chunks/studio-s6ymkf3q.js +14 -0
- package/dist/chunks/{studio-0x6f3nk9.js → studio-s7p5ccxa.js} +4 -4
- package/dist/chunks/{studio-1410q5dw.js → studio-s9jjap3x.js} +4 -4
- package/dist/chunks/{studio-evq47j2z.js → studio-t5hde1ws.js} +4 -4
- package/dist/chunks/studio-vj9yv897.js +5 -0
- package/dist/chunks/studio-wmak8xjw.js +5 -0
- package/dist/chunks/{studio-bnc50f9h.js → studio-wqsmvtqj.js} +4 -4
- package/dist/chunks/studio-x3z3rhej.js +5 -0
- package/dist/chunks/{studio-bg8pzprg.js → studio-xb55kpmy.js} +4 -4
- package/dist/chunks/studio-xxtdajmv.js +12 -0
- package/dist/chunks/studio-xxttcym1.js +5 -0
- package/dist/chunks/{studio-90zkgne5.js → studio-y2zsnzye.js} +7 -7
- package/dist/chunks/{studio-3qr08sxq.js → studio-y3tjh2xb.js} +3 -3
- package/dist/chunks/studio-y4f1rdsj.js +5 -0
- package/dist/chunks/studio-ybkd5w8k.js +5 -0
- package/dist/chunks/{studio-tpxcryf2.js → studio-yetr4gg1.js} +4 -4
- package/dist/chunks/studio-z295anhs.js +6 -0
- package/dist/chunks/studio-z89e6wpg.js +9 -0
- package/dist/chunks/{studio-5tet77de.js → studio-zbwr6prc.js} +3 -3
- package/dist/chunks/{studio-daksw8kh.js → studio-zdbsv5q2.js} +4 -4
- package/dist/chunks/{studio-abh9kfdh.js → studio-zvthj8hg.js} +4 -4
- package/dist/chunks/toast-2kn2vrn4.js +4 -0
- package/dist/chunks/{toast-host-g3r2s0kn.js → toast-host-3rxeyj3d.js} +3 -3
- package/dist/chunks/{tooltip-dj1pvgz7.js → tooltip-ghkxkasp.js} +3 -3
- package/dist/chunks/{tree-j0ebwr5s.js → tree-vw4nc63s.js} +2 -2
- package/dist/chunks/tsMode-7gngmamr.js +14 -0
- package/dist/chunks/workspace-gv0hxgsm.js +4 -0
- package/dist/chunks/workspace-home-j7e0mjy5.js +4 -0
- package/dist/chunks/{ws-client-arz2qsy9.js → ws-client-vs11sxc5.js} +3 -3
- package/dist/iframe-entry.js +14 -14
- package/dist/manifest.json +84 -83
- package/dist/studio.js +99 -98
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +12 -12
- package/src/browse/library-layouts.ts +9 -12
- package/src/browse/library-pane.ts +22 -16
- package/src/browse/library-source.ts +3 -4
- package/src/browse/preview-style.ts +2 -1
- package/src/canvas/canvas-live-render.ts +2 -5
- package/src/canvas/canvas-page-context.ts +5 -0
- package/src/canvas/canvas-render.ts +6 -1
- package/src/canvas/iframe-drop.ts +84 -1
- package/src/canvas/iframe-entry.ts +9 -6
- package/src/canvas/iframe-render.ts +13 -0
- package/src/collab/collab-session.ts +2 -2
- package/src/commands/levels.ts +1 -1
- package/src/content/entry-commands.ts +32 -27
- package/src/content/entry-editor.ts +46 -44
- package/src/content/entry-inspector.ts +15 -12
- package/src/content/entry-model.ts +3 -3
- package/src/content/entry-summaries.ts +5 -5
- package/src/content/hold-state.ts +172 -0
- package/src/content/page-summaries.ts +10 -14
- package/src/create/add-new-flow.ts +2 -1
- package/src/editor/convert-targets.ts +2 -23
- package/src/editor/inline-edit.ts +6 -1
- package/src/editor/repeater-scope.ts +333 -74
- package/src/editor/slash-menu.ts +35 -17
- package/src/files/files.ts +18 -0
- package/src/format/format-choices.ts +5 -5
- package/src/format/format-host.ts +35 -3
- package/src/grid/redirects-grid.ts +4 -4
- package/src/grid/sources/content-source.ts +42 -66
- package/src/locale/element-names.ts +131 -0
- package/src/panels/block-action-bar.ts +3 -4
- package/src/panels/dnd.ts +3 -1
- package/src/panels/elements-panel.ts +93 -36
- package/src/panels/events-panel.ts +6 -2
- package/src/panels/formula-workspace.ts +9 -0
- package/src/panels/imports-panel.ts +3 -2
- package/src/panels/navigator-panels.ts +10 -10
- package/src/panels/panel-registry.ts +3 -3
- package/src/panels/properties-panel.ts +127 -35
- package/src/panels/site-panel.ts +2 -1
- package/src/panels/statement-editor.ts +4 -0
- package/src/panels/style-panel.ts +2 -1
- package/src/panels/styles-panel.ts +2 -2
- package/src/panels/tab-strip.ts +29 -26
- package/src/platforms/cloud.ts +5 -2
- package/src/services/ai-command-tools.ts +2 -1
- package/src/services/ai-project-tools.ts +21 -8
- package/src/services/ai-tools.ts +5 -5
- package/src/services/ai-write-report.ts +22 -4
- package/src/services/context-manager.ts +110 -2
- package/src/services/document-assistant.ts +2 -2
- package/src/services/harness/chat-reducer.ts +9 -4
- package/src/services/jxn-language.ts +110 -0
- package/src/services/model-uri.ts +3 -0
- package/src/services/monaco-setup.ts +6 -2
- package/src/services/render-critic.ts +234 -12
- package/src/services/tool-executor.ts +16 -8
- package/src/settings/contributed-section.ts +2 -1
- package/src/settings/extension-commands.ts +2 -1
- package/src/settings/general-settings.ts +2 -2
- package/src/settings/settings-document.ts +5 -5
- package/src/shell.ts +1 -1
- package/src/studio.ts +28 -11
- package/src/style/variables-view.ts +2 -2
- package/src/surfaces/collections-panel.json +1 -1
- package/src/surfaces/collections-panel.ts +1 -1
- package/src/surfaces/entry-editor.json +10 -10
- package/src/surfaces/entry-editor.ts +22 -19
- package/src/surfaces/entry-inspector.json +11 -11
- package/src/surfaces/entry-inspector.ts +17 -10
- package/src/surfaces/panel-elements.json +466 -206
- package/src/surfaces/panel-elements.ts +61 -25
- package/src/surfaces/tab-strip.json +5 -5
- package/src/surfaces/tab-strip.ts +2 -2
- package/src/tabs/project-config.ts +13 -13
- package/src/tabs/tab.ts +7 -2
- package/src/types.ts +13 -2
- package/src/ui/expression-editor.ts +10 -5
- package/src/ui/schema-form.ts +18 -1
- package/src/utils/edit-display.ts +27 -1
- package/src/view.ts +9 -2
- package/src/workspace/tab-workspace.ts +2 -2
- package/src/workspace/workspace-back.ts +2 -2
- package/dist/chunks/2020-906vx2dq.js +0 -4
- package/dist/chunks/adapter-hnvad61x.js +0 -4
- package/dist/chunks/add-new-flow-v0pm96mr.js +0 -4
- package/dist/chunks/cf-settings-mkbcz4z2.js +0 -4
- package/dist/chunks/color-04361ttk.js +0 -4
- package/dist/chunks/color-field-qv5r2b16.js +0 -4
- package/dist/chunks/components-w5zqwva1.js +0 -4
- package/dist/chunks/content-source-g38w0d3f.js +0 -4
- package/dist/chunks/convert-to-repeater-r8sfxjjm.js +0 -4
- package/dist/chunks/editor-wvf5e6j9.js +0 -4
- package/dist/chunks/entry-commands-t13dyw3c.js +0 -4
- package/dist/chunks/extension-sections-vjzw46xb.js +0 -4
- package/dist/chunks/file-ops-1sghzgcr.js +0 -4
- package/dist/chunks/files-zrqtgt41.js +0 -4
- package/dist/chunks/format-host-9gy76erh.js +0 -4
- package/dist/chunks/fs-events-45rhg3me.js +0 -4
- package/dist/chunks/grid-open-t4fq6bbm.js +0 -4
- package/dist/chunks/iframe-entry-42hpmwz5.js +0 -5
- package/dist/chunks/iframe-host-9aq8ze3q.js +0 -4
- package/dist/chunks/index-f9qr7kzh.js +0 -4
- package/dist/chunks/jsonMode-vj30te2h.js +0 -13
- package/dist/chunks/jx-validate-r4ax11e3.js +0 -4
- package/dist/chunks/layers-m49nmwvx.js +0 -4
- package/dist/chunks/layers-panel-zr92pwdp.js +0 -4
- package/dist/chunks/lit-html-k2mb9k0r.js +0 -4
- package/dist/chunks/media-library-j74rt0w4.js +0 -4
- package/dist/chunks/media-open-mypr0k6b.js +0 -4
- package/dist/chunks/media-picker-pemtbsjv.js +0 -4
- package/dist/chunks/menu-d2jxpgma.js +0 -4
- package/dist/chunks/monaco-buffer-pa0g6ax7.js +0 -4
- package/dist/chunks/monaco-setup-0hw9f835.js +0 -4
- package/dist/chunks/notify-bwehrp7q.js +0 -4
- package/dist/chunks/parse-hee7ne9b.js +0 -4
- package/dist/chunks/platform-kv0k65cy.js +0 -4
- package/dist/chunks/popover-9tf4cjrk.js +0 -4
- package/dist/chunks/publish-panel-vg1n880b.js +0 -4
- package/dist/chunks/publish-quick-4fwngwrw.js +0 -4
- package/dist/chunks/publish-workspace-jv4w2bx2.js +0 -4
- package/dist/chunks/quick-search-nh29rt8a.js +0 -4
- package/dist/chunks/references-vqyr5s9x.js +0 -4
- package/dist/chunks/right-panel-3ws9f2w0.js +0 -4
- package/dist/chunks/source-control-h3hcs5gy.js +0 -4
- package/dist/chunks/studio-0khd8xtx.js +0 -4
- package/dist/chunks/studio-1ctnw3xv.js +0 -5
- package/dist/chunks/studio-1ks5d9y4.js +0 -5
- package/dist/chunks/studio-1y9mab9m.js +0 -5
- package/dist/chunks/studio-2kpxm0eh.js +0 -7
- package/dist/chunks/studio-2zz4qbv9.js +0 -5
- package/dist/chunks/studio-3pz4t5a2.js +0 -5
- package/dist/chunks/studio-4f7thq0p.js +0 -5
- package/dist/chunks/studio-61rg2cz5.js +0 -5
- package/dist/chunks/studio-7rrdbvex.js +0 -5
- package/dist/chunks/studio-9c6cbq2c.js +0 -4
- package/dist/chunks/studio-9dq7rwc7.js +0 -5
- package/dist/chunks/studio-9gr7xs9r.js +0 -6
- package/dist/chunks/studio-a88ej93p.js +0 -7
- package/dist/chunks/studio-acer0g8w.js +0 -5
- package/dist/chunks/studio-az3wvyh2.js +0 -5
- package/dist/chunks/studio-brh8d2pr.js +0 -5
- package/dist/chunks/studio-c2fa783p.js +0 -9
- package/dist/chunks/studio-cfnn70h1.js +0 -5
- package/dist/chunks/studio-cqxj4fcy.js +0 -5
- package/dist/chunks/studio-cw11h078.js +0 -5
- package/dist/chunks/studio-dn56z7sn.js +0 -5
- package/dist/chunks/studio-egnjpyde.js +0 -9
- package/dist/chunks/studio-ejrypvmq.js +0 -5
- package/dist/chunks/studio-frc16j8v.js +0 -10
- package/dist/chunks/studio-gnazwtv3.js +0 -5
- package/dist/chunks/studio-hfqpfmpk.js +0 -5
- package/dist/chunks/studio-hh394phe.js +0 -5
- package/dist/chunks/studio-j0zf5x2x.js +0 -5
- package/dist/chunks/studio-j5fcp6gj.js +0 -5
- package/dist/chunks/studio-jd1qb1st.js +0 -7
- package/dist/chunks/studio-k0xzrse2.js +0 -64
- package/dist/chunks/studio-k1xqrgm5.js +0 -5
- package/dist/chunks/studio-k3we3kqb.js +0 -5
- package/dist/chunks/studio-knsjyx7n.js +0 -5
- package/dist/chunks/studio-mrjtnm62.js +0 -5
- package/dist/chunks/studio-n9qba0gx.js +0 -5
- package/dist/chunks/studio-nzemfbkk.js +0 -14
- package/dist/chunks/studio-pwctzka3.js +0 -16
- package/dist/chunks/studio-q80fg1d6.js +0 -12
- package/dist/chunks/studio-q9hx2qp0.js +0 -5
- package/dist/chunks/studio-qrzmfaf6.js +0 -5
- package/dist/chunks/studio-r6mx7vm5.js +0 -7
- package/dist/chunks/studio-swedpd82.js +0 -5
- package/dist/chunks/studio-tmfcn347.js +0 -6
- package/dist/chunks/studio-v5wktj6f.js +0 -5
- package/dist/chunks/studio-vpevkfxw.js +0 -5
- package/dist/chunks/studio-wqfaqw4m.js +0 -5
- package/dist/chunks/studio-xpx91fby.js +0 -6
- package/dist/chunks/studio-xva3hzkv.js +0 -5
- package/dist/chunks/studio-z3fztxrp.js +0 -9
- package/dist/chunks/studio-z9453ypn.js +0 -6
- package/dist/chunks/toast-w11qpkyz.js +0 -4
- package/dist/chunks/tsMode-jg1dtphj.js +0 -14
- package/dist/chunks/workspace-6ztqcrsh.js +0 -4
- package/dist/chunks/workspace-home-rse9h8a0.js +0 -4
- package/src/content/draft-state.ts +0 -108
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jx Notation in the Code view: a Monarch grammar, with TypeScript inside a multi-line raw string.
|
|
3
|
+
*
|
|
4
|
+
* Multi-line raw strings are where a `.jxn` file keeps code (`spec.md` §22.3), so highlighting one
|
|
5
|
+
* as TypeScript is the common case and not a guess about a particular file.
|
|
6
|
+
*
|
|
7
|
+
* @docs framework/concepts/jxn-files
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { languages } from "monaco-editor/editor";
|
|
11
|
+
|
|
12
|
+
/** The language id, as `monacoLangForPath` answers it. */
|
|
13
|
+
export const JXN_LANGUAGE_ID = "jxn";
|
|
14
|
+
|
|
15
|
+
/** Comments and brackets, which is what typing and folding need to know. */
|
|
16
|
+
export const JXN_LANGUAGE_CONFIGURATION: languages.LanguageConfiguration = {
|
|
17
|
+
autoClosingPairs: [
|
|
18
|
+
{ close: "}", open: "{" },
|
|
19
|
+
{ close: ")", open: "(" },
|
|
20
|
+
{ close: '"', open: '"' },
|
|
21
|
+
],
|
|
22
|
+
brackets: [
|
|
23
|
+
["{", "}"],
|
|
24
|
+
["(", ")"],
|
|
25
|
+
],
|
|
26
|
+
comments: { blockComment: ["/*", "*/"], lineComment: "//" },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** The tokenizer. */
|
|
30
|
+
export const JXN_MONARCH: languages.IMonarchLanguage = {
|
|
31
|
+
defaultToken: "",
|
|
32
|
+
// Monarch otherwise starts in the first state listed, and these are sorted.
|
|
33
|
+
start: "root",
|
|
34
|
+
tokenizer: {
|
|
35
|
+
blockComment: [
|
|
36
|
+
[/[^/*]+/u, "comment"],
|
|
37
|
+
[/\/\*/u, "comment", "@push"],
|
|
38
|
+
[/\*\//u, "comment", "@pop"],
|
|
39
|
+
[/[/*]/u, "comment"],
|
|
40
|
+
],
|
|
41
|
+
quoted: [
|
|
42
|
+
[/[^\\"]+/u, "string"],
|
|
43
|
+
[/\\./u, "string.escape"],
|
|
44
|
+
[/"/u, "string", "@pop"],
|
|
45
|
+
],
|
|
46
|
+
quotedLines: [
|
|
47
|
+
[/"""/u, "string", "@pop"],
|
|
48
|
+
[/\\./u, "string.escape"],
|
|
49
|
+
[/./u, "string"],
|
|
50
|
+
],
|
|
51
|
+
raw: [
|
|
52
|
+
[/"#+/u, { cases: { "$0==$S2": { next: "@pop", token: "string" }, "@default": "string" } }],
|
|
53
|
+
[/[^"]+/u, "string"],
|
|
54
|
+
[/"/u, "string"],
|
|
55
|
+
],
|
|
56
|
+
rawLines: [
|
|
57
|
+
[
|
|
58
|
+
/"""#+/u,
|
|
59
|
+
{
|
|
60
|
+
cases: {
|
|
61
|
+
"$0==$S2": { next: "@pop", nextEmbedded: "@pop", token: "string.quote" },
|
|
62
|
+
"@default": "",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
[/[^"]+/u, ""],
|
|
67
|
+
[/"/u, ""],
|
|
68
|
+
],
|
|
69
|
+
root: [
|
|
70
|
+
[/\/\/.*$/u, "comment"],
|
|
71
|
+
[/\/\*/u, "comment", "@blockComment"],
|
|
72
|
+
[/\/-/u, "comment"],
|
|
73
|
+
[/\((?:array|fn|object|on|ref)\)/u, "type"],
|
|
74
|
+
[/\([^)\s]*\)/u, "invalid"],
|
|
75
|
+
[/#"""/u, { next: '@rawLines."""#', nextEmbedded: "typescript", token: "string.quote" }],
|
|
76
|
+
[/##+"""/u, { next: '@rawLines."""$0', nextEmbedded: "typescript", token: "string.quote" }],
|
|
77
|
+
[/#+"/u, { next: '@raw."$0', token: "string" }],
|
|
78
|
+
[/"""/u, "string", "@quotedLines"],
|
|
79
|
+
[/"/u, "string", "@quoted"],
|
|
80
|
+
[/#(?:true|false|null|inf|-inf|nan)\b/u, "keyword"],
|
|
81
|
+
[/[-+]?\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][-+]?\d+)?/u, "number"],
|
|
82
|
+
[/[{};]/u, "delimiter"],
|
|
83
|
+
[/\$[^\s=(){};"]*/u, "keyword"],
|
|
84
|
+
[/[^\s=(){};"#]+(?==)/u, "attribute.name"],
|
|
85
|
+
[/[^\s=(){};"#]+/u, "identifier"],
|
|
86
|
+
[/[=]/u, "delimiter"],
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/** The part of Monaco's API registering a language uses. */
|
|
92
|
+
export type MonacoLanguages = Pick<
|
|
93
|
+
typeof languages,
|
|
94
|
+
"register" | "setLanguageConfiguration" | "setMonarchTokensProvider"
|
|
95
|
+
>;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Teach Monaco the language.
|
|
99
|
+
*
|
|
100
|
+
* @param languages `monaco.languages`. Absent under a double of Monaco that has no language API,
|
|
101
|
+
* and there is nothing to teach then.
|
|
102
|
+
*/
|
|
103
|
+
export function registerJxnLanguage(languages?: MonacoLanguages): void {
|
|
104
|
+
if (!languages) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
languages.register({ extensions: [".jxn"], id: JXN_LANGUAGE_ID });
|
|
108
|
+
languages.setLanguageConfiguration(JXN_LANGUAGE_ID, JXN_LANGUAGE_CONFIGURATION);
|
|
109
|
+
languages.setMonarchTokensProvider(JXN_LANGUAGE_ID, JXN_MONARCH);
|
|
110
|
+
}
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* schema completion with it.
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
|
-
import "monaco-editor/editor";
|
|
38
|
+
import * as monacoApi from "monaco-editor/editor";
|
|
39
39
|
// Core widget, icons, tokenization.
|
|
40
40
|
import "monaco-editor/features/codeEditor/register";
|
|
41
41
|
import "monaco-editor/features/codicon/register";
|
|
@@ -83,6 +83,8 @@ import projectSchema from "@jxsuite/schema/project-schema.json";
|
|
|
83
83
|
import type { JsonObject } from "@jxsuite/schema/types";
|
|
84
84
|
import type { ProjectSchemasResponse } from "../types";
|
|
85
85
|
import { bundleUrl } from "./bundle-base";
|
|
86
|
+
import { PROJECT_FILE_NAME } from "@jxsuite/schema/project-file";
|
|
87
|
+
import { registerJxnLanguage } from "./jxn-language";
|
|
86
88
|
|
|
87
89
|
/* Re-exported for the modules that already imported it from here. New callers should reach for
|
|
88
90
|
`./model-uri` directly — it is Monaco-free, and importing this module loads the editor. */
|
|
@@ -150,6 +152,8 @@ if (documentFonts?.ready) {
|
|
|
150
152
|
});
|
|
151
153
|
}
|
|
152
154
|
|
|
155
|
+
registerJxnLanguage(monacoApi.languages);
|
|
156
|
+
|
|
153
157
|
/** Folder globs whose JSON files validate against the (per-project or core) document schema. */
|
|
154
158
|
const DOCUMENT_FILE_MATCH = [
|
|
155
159
|
"pages/*.json",
|
|
@@ -205,7 +209,7 @@ function applyJsonSchemas(documentSchema: JsonObject, projectJsonSchema: JsonObj
|
|
|
205
209
|
uri: "https://jxsuite.com/schema/v1",
|
|
206
210
|
},
|
|
207
211
|
{
|
|
208
|
-
fileMatch: [
|
|
212
|
+
fileMatch: [PROJECT_FILE_NAME],
|
|
209
213
|
schema: projectJsonSchema,
|
|
210
214
|
uri: "https://jxsuite.com/schema/project/v1",
|
|
211
215
|
},
|
|
@@ -10,19 +10,41 @@
|
|
|
10
10
|
* expressions). Does NOT detect empty/zero-node output or deep-render custom element internals
|
|
11
11
|
* (connectedCallback doesn't fire on detached nodes).
|
|
12
12
|
*
|
|
13
|
+
* A page is drawn as the build would draw it, so a page that builds is not refused for what only
|
|
14
|
+
* the build supplies: its data is awaited, a dynamic route is drawn with its first entry, and
|
|
15
|
+
* `$page`, `$site` and project state are injected. Live data is the exception. A `timing: "server"`
|
|
16
|
+
* function is never called here and a `Request` is never sent (specs/ai.md §3.1), so both read as
|
|
17
|
+
* placeholders.
|
|
18
|
+
*
|
|
13
19
|
* @license MIT
|
|
20
|
+
* @docs studio/ai/document-assistant
|
|
14
21
|
*/
|
|
15
22
|
|
|
16
23
|
import {
|
|
17
24
|
buildScope,
|
|
25
|
+
lookupsSettled,
|
|
18
26
|
renderNode,
|
|
19
27
|
runScoped,
|
|
20
28
|
setResolveToken,
|
|
21
29
|
setSkipServerFunctions,
|
|
22
30
|
setTemplateErrorHandler,
|
|
23
31
|
} from "@jxsuite/runtime";
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
32
|
+
import { isJsonObject, isServerFnDef, isString } from "@jxsuite/schema/guards";
|
|
33
|
+
import { injectContext } from "@jxsuite/site/context";
|
|
34
|
+
import { documentUrlPattern } from "@jxsuite/site/routes";
|
|
35
|
+
import type { JxScope } from "@jxsuite/runtime/types";
|
|
36
|
+
import type { JxDocument, JxMutableNode, JxStateDefinition } from "@jxsuite/schema/types";
|
|
37
|
+
import { documentBase, hostResolveToken } from "../canvas/canvas-origin";
|
|
38
|
+
import { isPagePath, pageContextFor } from "../canvas/canvas-page-context";
|
|
39
|
+
import {
|
|
40
|
+
dynamicRouteParams,
|
|
41
|
+
loadParamValues,
|
|
42
|
+
pagePathsDef,
|
|
43
|
+
paramBoundStateKeys,
|
|
44
|
+
substitutePreviewParams,
|
|
45
|
+
} from "../page-params";
|
|
46
|
+
import { projectState } from "../store";
|
|
47
|
+
import type { RenderSource } from "./ai-write-report";
|
|
26
48
|
|
|
27
49
|
/**
|
|
28
50
|
* Translate a render-time error into an actionable message the model can fix.
|
|
@@ -49,39 +71,239 @@ function translateRenderError(cause: unknown): string {
|
|
|
49
71
|
return `Render error: ${msg}\n → Fix: The document is schema-valid but fails to render. Review the last change for typos in $ref paths, template expressions, or event handler definitions.`;
|
|
50
72
|
}
|
|
51
73
|
|
|
74
|
+
/** How long a check waits for a document's data before it stops judging its templates. */
|
|
75
|
+
const LOOKUP_WAIT_MS = 5000;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Wait for the lookups in flight, for at most `waitMs`.
|
|
79
|
+
*
|
|
80
|
+
* @param {number} waitMs
|
|
81
|
+
* @returns {Promise<boolean>} Whether they all settled in time
|
|
82
|
+
*/
|
|
83
|
+
async function lookupsAnswered(waitMs: number): Promise<boolean> {
|
|
84
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
85
|
+
const expired = new Promise<boolean>((answer) => {
|
|
86
|
+
timer = setTimeout(answer, waitMs, false);
|
|
87
|
+
});
|
|
88
|
+
const answered = await Promise.race([lookupsSettled().then(() => true), expired]);
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
return answered;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* What live data reads as during a check: anything may be read from it or called on it, and it
|
|
95
|
+
* prints as nothing, so a template over live data evaluates and every other template on the page is
|
|
96
|
+
* still judged.
|
|
97
|
+
*
|
|
98
|
+
* `then` and the reactivity library's `__v_` flags read as absent: a truthy `then` would make it a
|
|
99
|
+
* thenable that never settles, and a truthy `__v_raw` sends `toRaw` round in a circle.
|
|
100
|
+
*
|
|
101
|
+
* @returns {() => void}
|
|
102
|
+
*/
|
|
103
|
+
function liveDataPlaceholder(): () => void {
|
|
104
|
+
const placeholder: () => void = new Proxy(() => placeholder, {
|
|
105
|
+
get(_target, key) {
|
|
106
|
+
if (key === Symbol.toPrimitive) {
|
|
107
|
+
return () => "";
|
|
108
|
+
}
|
|
109
|
+
if (key === Symbol.iterator) {
|
|
110
|
+
return Array.prototype[Symbol.iterator].bind([]);
|
|
111
|
+
}
|
|
112
|
+
return isString(key) && key !== "then" && !key.startsWith("__v_") ? placeholder : undefined;
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
return placeholder;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Whether an entry's value is live data, which only a person's own action may fetch. */
|
|
119
|
+
function isLiveData(entry: JxStateDefinition): boolean {
|
|
120
|
+
return (
|
|
121
|
+
isServerFnDef(entry) ||
|
|
122
|
+
(isJsonObject(entry) && entry.$prototype === "Request" && !isString(entry.$src))
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The class entry a template reads that came back with no data, if it reads one. The template is
|
|
128
|
+
* what connects them: an unrelated broken template beside a failed lookup is still its own
|
|
129
|
+
* mistake.
|
|
130
|
+
*
|
|
131
|
+
* @param {JxDocument} built
|
|
132
|
+
* @param {JxScope} state
|
|
133
|
+
* @param {string} template
|
|
134
|
+
* @returns {{ key: string; from: string } | null}
|
|
135
|
+
*/
|
|
136
|
+
function emptyLookupRead(
|
|
137
|
+
built: JxDocument,
|
|
138
|
+
state: JxScope,
|
|
139
|
+
template: string,
|
|
140
|
+
): { key: string; from: string } | null {
|
|
141
|
+
const reads = new Set(template.match(/state\.[\w$]+/g));
|
|
142
|
+
for (const [key, entry] of Object.entries(built.state ?? {})) {
|
|
143
|
+
if (
|
|
144
|
+
reads.has(`state.${key}`) &&
|
|
145
|
+
isJsonObject(entry) &&
|
|
146
|
+
isString(entry.$prototype) &&
|
|
147
|
+
entry.$prototype !== "Function" &&
|
|
148
|
+
(state[key] ?? null) === null
|
|
149
|
+
) {
|
|
150
|
+
return { from: isString(entry.$src) ? entry.$src : entry.$prototype, key };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The first entry of each route parameter a document declares, as the preview picker opens with.
|
|
158
|
+
*
|
|
159
|
+
* @param {JxDocument} doc
|
|
160
|
+
* @param {RenderSource} source
|
|
161
|
+
* @returns {Promise<Record<string, string>>}
|
|
162
|
+
*/
|
|
163
|
+
async function sampleRouteParams(
|
|
164
|
+
doc: JxMutableNode,
|
|
165
|
+
{ documentPath, frontmatter }: RenderSource,
|
|
166
|
+
): Promise<Record<string, string>> {
|
|
167
|
+
const paths = pagePathsDef({ document: doc, frontmatter: frontmatter ?? null });
|
|
168
|
+
const params: Record<string, string> = {};
|
|
169
|
+
for (const [name, values] of Object.entries(await loadParamValues(documentPath, paths))) {
|
|
170
|
+
const [first] = values;
|
|
171
|
+
if (first !== undefined) {
|
|
172
|
+
params[name] = first;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return params;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A document as the build would hand it to the renderer. A rebuild: the document may be the live
|
|
180
|
+
* tree of an open tab, which must not gain keys it would then save.
|
|
181
|
+
*
|
|
182
|
+
* @param {JxDocument} doc
|
|
183
|
+
* @param {RenderSource} source
|
|
184
|
+
* @returns {Promise<{ built: JxDocument; sampled: boolean }>} `sampled` is false when a route
|
|
185
|
+
* parameter has no entry to stand for it, so the data its templates read cannot be looked up
|
|
186
|
+
*/
|
|
187
|
+
async function asBuilt(
|
|
188
|
+
doc: JxDocument,
|
|
189
|
+
source: RenderSource,
|
|
190
|
+
): Promise<{ built: JxDocument; sampled: boolean }> {
|
|
191
|
+
const { documentPath } = source;
|
|
192
|
+
/* SAFETY: a candidate is a JSON tree, and everything below rebuilds it rather than writing to it,
|
|
193
|
+
so the mutable type is only what these shared helpers are declared over. */
|
|
194
|
+
const candidate = doc as JxMutableNode;
|
|
195
|
+
const params = await sampleRouteParams(candidate, source);
|
|
196
|
+
let built = substitutePreviewParams(candidate, params, documentPath);
|
|
197
|
+
|
|
198
|
+
const projectConfig = projectState?.projectConfig;
|
|
199
|
+
const drawnAsPage =
|
|
200
|
+
documentPath && (isPagePath(documentPath) || documentPath.startsWith("layouts/"));
|
|
201
|
+
if (drawnAsPage && projectConfig && projectState?.isSiteProject) {
|
|
202
|
+
built = { ...built, state: { ...built.state } };
|
|
203
|
+
if (built.imports) {
|
|
204
|
+
built.imports = { ...built.imports };
|
|
205
|
+
}
|
|
206
|
+
/* SAFETY: as on the canvas: `injectContext` writes `state`, `$media` and `imports`, all of which
|
|
207
|
+
the copy above owns. */
|
|
208
|
+
injectContext(built as JxDocument, projectConfig, {
|
|
209
|
+
urlPattern: documentUrlPattern(documentPath),
|
|
210
|
+
});
|
|
211
|
+
const context = await pageContextFor(
|
|
212
|
+
{ documentPath, isEntry: false, lang: doc.$lang, params, title: doc.title },
|
|
213
|
+
projectConfig,
|
|
214
|
+
);
|
|
215
|
+
if (context) {
|
|
216
|
+
built = { ...built, state: { ...built.state, ...context } };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const sampled =
|
|
221
|
+
dynamicRouteParams(documentPath).every((name) => name in params) &&
|
|
222
|
+
paramBoundStateKeys(built.state ?? null).length === 0;
|
|
223
|
+
/* SAFETY: the same document, rebuilt member for member; its schema has not changed. */
|
|
224
|
+
return { built: built as JxDocument, sampled };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The URL a document's relative references resolve from, when one can be formed. A check is not
|
|
229
|
+
* failed for lacking one: a document with no relative reference does not need it.
|
|
230
|
+
*
|
|
231
|
+
* @param {RenderSource} source
|
|
232
|
+
* @returns {string | undefined}
|
|
233
|
+
*/
|
|
234
|
+
function baseOf({ documentPath }: RenderSource): string | undefined {
|
|
235
|
+
const base = documentBase(projectState?.projectRoot);
|
|
236
|
+
return documentPath && URL.canParse(base) ? new URL(documentPath, base).href : undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
52
239
|
/**
|
|
53
240
|
* Attempt a detached render of a Jx document. Returns { ok: true } on success or { ok: false,
|
|
54
241
|
* error: string } with an actionable message on failure.
|
|
55
242
|
*
|
|
56
243
|
* @param {import("@jxsuite/schema/types").JxDocument} doc
|
|
244
|
+
* @param {RenderSource} [source] - Where the document lives, when it lives anywhere yet
|
|
245
|
+
* @param {number} [waitMs] - How long to wait for the document's data
|
|
57
246
|
* @returns {Promise<{ ok: true } | { ok: false; error: string }>}
|
|
58
247
|
*/
|
|
59
248
|
export async function renderCheck(
|
|
60
249
|
doc: JxDocument,
|
|
250
|
+
source: RenderSource = {},
|
|
251
|
+
waitMs = LOOKUP_WAIT_MS,
|
|
61
252
|
): Promise<{ ok: true } | { ok: false; error: string }> {
|
|
62
253
|
let stopRender: (() => void) | null = null;
|
|
63
|
-
/* A binding that throws no longer unwinds the render (spec.md §6.1) — it renders empty and waits
|
|
64
|
-
for its data — so the throw is collected here instead. The first one is the verdict: a page
|
|
65
|
-
whose template can never evaluate is exactly what this check exists to refuse. */
|
|
66
|
-
const bindingErrors: Error[] = [];
|
|
67
|
-
setTemplateErrorHandler((error) => {
|
|
68
|
-
bindingErrors.push(error);
|
|
69
|
-
});
|
|
70
254
|
try {
|
|
71
255
|
setSkipServerFunctions(true);
|
|
72
256
|
// The desktop dev proxy refuses a class resolve without the token the canvas carries.
|
|
73
257
|
setResolveToken(hostResolveToken());
|
|
74
258
|
|
|
75
|
-
const
|
|
259
|
+
const { built, sampled } = await asBuilt(doc, source);
|
|
260
|
+
const base = baseOf(source) ?? location.href;
|
|
261
|
+
/* This call's own context rather than `setSkipAutoRequests`, which is realm-wide: a Library
|
|
262
|
+
preview draws in this same realm, and would silently stop fetching. */
|
|
263
|
+
const state = await buildScope(built, {}, base, {
|
|
264
|
+
base,
|
|
265
|
+
media: null,
|
|
266
|
+
root: null,
|
|
267
|
+
skipAutoRequests: true,
|
|
268
|
+
});
|
|
269
|
+
for (const [key, entry] of Object.entries(built.state ?? {})) {
|
|
270
|
+
if (isLiveData(entry)) {
|
|
271
|
+
state[key] = liveDataPlaceholder();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* The build resolves a page's data before its templates run, and here the data is a lookup that
|
|
276
|
+
has only just started. Rendering now would read `null` and refuse a page that builds. */
|
|
277
|
+
const answered = await lookupsAnswered(waitMs);
|
|
278
|
+
|
|
279
|
+
/* A binding that throws no longer unwinds the render (spec.md §6.1) — it renders empty and
|
|
280
|
+
waits for its data — so the throw is collected here instead. The first one is the verdict: a
|
|
281
|
+
page whose template can never evaluate is exactly what this check exists to refuse. Only for
|
|
282
|
+
the synchronous render: anything else this realm draws during the wait is not this document. */
|
|
283
|
+
const bindingErrors: { error: Error; template: string }[] = [];
|
|
284
|
+
setTemplateErrorHandler((error, template) => {
|
|
285
|
+
bindingErrors.push({ error, template });
|
|
286
|
+
});
|
|
76
287
|
|
|
77
288
|
const container = document.createElement("div");
|
|
78
289
|
const { stop } = runScoped(() => {
|
|
79
|
-
container.append(renderNode(
|
|
290
|
+
container.append(renderNode(built, state));
|
|
80
291
|
});
|
|
81
292
|
stopRender = stop;
|
|
82
293
|
|
|
294
|
+
/* With a lookup still out, or no entry to look up, a throw may be nothing but the data being
|
|
295
|
+
absent, and refusing would block a valid write. A live binding recovers if that is what it was. */
|
|
83
296
|
const [first] = bindingErrors;
|
|
84
|
-
|
|
297
|
+
if (!first || !answered || !sampled) {
|
|
298
|
+
return { ok: true };
|
|
299
|
+
}
|
|
300
|
+
const empty = emptyLookupRead(built, state, first.template);
|
|
301
|
+
return {
|
|
302
|
+
error: empty
|
|
303
|
+
? `Render error: ${first.error.message}\n → Fix: state.${empty.key} has no data: its lookup through ${empty.from} failed or came back empty, so this template has nothing to read. Check that $src and the entry's config. If the data can legitimately be empty, guard the read, for example state.${empty.key}?.name.`
|
|
304
|
+
: translateRenderError(first.error),
|
|
305
|
+
ok: false,
|
|
306
|
+
};
|
|
85
307
|
} catch (error) {
|
|
86
308
|
return { ok: false, error: translateRenderError(error) };
|
|
87
309
|
} finally {
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
import type { InteractionStore } from "./harness/interaction-store";
|
|
23
23
|
import type { createChatState } from "@jxsuite/ai/chat-state";
|
|
24
24
|
import { DEFAULT_TURN_POLICY, assistantActorId, runTurn } from "@jxsuite/ai/harness";
|
|
25
|
-
import type { TurnInput, TurnRun } from "@jxsuite/ai/harness";
|
|
26
|
-
import { toChatMessages, toOpenAITools } from "@jxsuite/ai/messages";
|
|
25
|
+
import type { TurnInput, TurnPolicy, TurnRun } from "@jxsuite/ai/harness";
|
|
26
|
+
import { toChatMessages, toOpenAIMessages, toOpenAITools } from "@jxsuite/ai/messages";
|
|
27
27
|
import type { StreamingClient } from "@jxsuite/ai/streaming-client";
|
|
28
28
|
import { createSessionFacts } from "@jxsuite/ai/tools";
|
|
29
29
|
import type { SessionFacts, ToolRegistry } from "@jxsuite/ai/tools";
|
|
30
30
|
|
|
31
31
|
import type { Tab } from "../tabs/tab";
|
|
32
32
|
import { openBatchLane } from "../tabs/transact";
|
|
33
|
-
import { estimatePromptTokens } from "./context-manager";
|
|
33
|
+
import { estimatePromptTokens, shedToolResults } from "./context-manager";
|
|
34
34
|
import { fileTurn, openTurnLedger, turnAnchor } from "./ai-writes";
|
|
35
35
|
import { applyHarnessEvent } from "./harness/chat-reducer";
|
|
36
36
|
import { studioTurnHooks } from "./harness/turn-hooks";
|
|
@@ -52,6 +52,8 @@ interface RunAgentLoopOptions {
|
|
|
52
52
|
session?: SessionFacts;
|
|
53
53
|
/** Where a call that needs the author waits on them. Without one, such a call is refused. */
|
|
54
54
|
interactions?: InteractionStore;
|
|
55
|
+
/** Overrides on Studio's policy, for a run with bounds of its own. */
|
|
56
|
+
policy?: Partial<TurnPolicy>;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
/**
|
|
@@ -67,6 +69,7 @@ export async function runAgentLoop({
|
|
|
67
69
|
getTab,
|
|
68
70
|
session = createSessionFacts(),
|
|
69
71
|
interactions,
|
|
72
|
+
policy,
|
|
70
73
|
}: RunAgentLoopOptions): Promise<void> {
|
|
71
74
|
/* The ledger is filed under the turn's last DRAWN assistant message (see services/ai-writes), so
|
|
72
75
|
the scan starts at the message this turn answers. */
|
|
@@ -103,9 +106,13 @@ export async function runAgentLoop({
|
|
|
103
106
|
system: [{ text: systemPrompt }],
|
|
104
107
|
/* Projected from the chat store, the transcript of record. The streaming client is read on
|
|
105
108
|
every round, and the turn's own signal is the host's, so a request is the one it was. */
|
|
106
|
-
model: (request) =>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
model: (request) => {
|
|
110
|
+
/* A long turn must not outgrow the window between two sends: the trim only runs at a send. */
|
|
111
|
+
shedToolResults(chatState, systemPrompt);
|
|
112
|
+
const messages = chatState.toMessagesArray();
|
|
113
|
+
return streamingClient.streamChat(
|
|
114
|
+
/* A closing round's note is on no transcript, so it joins here, for this request only. */
|
|
115
|
+
request.closing ? [...messages, ...toOpenAIMessages([request.closing])] : messages,
|
|
109
116
|
toOpenAITools(request.tools),
|
|
110
117
|
systemPrompt,
|
|
111
118
|
/* SAFETY: the one production caller, `document-assistant.ts`, always passes its turn
|
|
@@ -113,11 +120,12 @@ export async function runAgentLoop({
|
|
|
113
120
|
doubles record the absent signal rather than reading it — which the agent-trace
|
|
114
121
|
goldens (`signal: "none"`) pin. */
|
|
115
122
|
signal as AbortSignal,
|
|
116
|
-
)
|
|
123
|
+
);
|
|
124
|
+
},
|
|
117
125
|
modelInfo: { family: "openai-compat", model: chatState.model },
|
|
118
126
|
tools: toolRegistry,
|
|
119
127
|
turnId: ledger.turnId,
|
|
120
|
-
policy: { estimateTokens: estimatePromptTokens },
|
|
128
|
+
policy: { estimateTokens: estimatePromptTokens, parallelReadOnly: true, ...policy },
|
|
121
129
|
hooks: studioTurnHooks({
|
|
122
130
|
superseded: () =>
|
|
123
131
|
turnUserId !== undefined && !chatState.messages.some((m) => m.id === turnUserId),
|
|
@@ -61,6 +61,7 @@ import type {
|
|
|
61
61
|
ContributedSurfaceHandle,
|
|
62
62
|
ContributedView,
|
|
63
63
|
} from "../surfaces/settings-contributed";
|
|
64
|
+
import { projectConfigPath } from "../tabs/tab";
|
|
64
65
|
|
|
65
66
|
// ─── Contribution shape ───────────────────────────────────────────────────────
|
|
66
67
|
|
|
@@ -258,7 +259,7 @@ async function saveProjectConfig(base: string, rerender: () => void) {
|
|
|
258
259
|
fault, so it is a problem of its own rather than an error parked on the user's field. */
|
|
259
260
|
notify.warn(`Could not validate project.json — ${errorMessage(error)}`, {
|
|
260
261
|
key: "settings:validator",
|
|
261
|
-
path:
|
|
262
|
+
path: projectConfigPath(),
|
|
262
263
|
source: "Settings",
|
|
263
264
|
tier: "problem",
|
|
264
265
|
});
|
|
@@ -43,6 +43,7 @@ import { notify } from "../services/notify";
|
|
|
43
43
|
import { notifySettingsDocument } from "./section-registry";
|
|
44
44
|
import { updateSiteConfig } from "../site-context";
|
|
45
45
|
import type { AnyCommand, CommandRegistry } from "../commands/registry";
|
|
46
|
+
import { projectConfigPath } from "../tabs/tab";
|
|
46
47
|
|
|
47
48
|
/** The package an extension operation is running for, or null. */
|
|
48
49
|
let _inFlight: string | null = null;
|
|
@@ -168,7 +169,7 @@ export async function enableExtension(specifier: string): Promise<void> {
|
|
|
168
169
|
}
|
|
169
170
|
await updateSiteConfig({ extensions: [...enabledSpecifiers(), row.specifier] });
|
|
170
171
|
/* Set after the write resolved, so the latch never claims a file the write did not reach. */
|
|
171
|
-
_lastEnableWrote = installed ? [
|
|
172
|
+
_lastEnableWrote = installed ? [projectConfigPath(), "package.json"] : [projectConfigPath()];
|
|
172
173
|
} finally {
|
|
173
174
|
_inFlight = null;
|
|
174
175
|
notifySettingsDocument();
|
|
@@ -25,7 +25,7 @@ import { runActiveReported } from "../commands/run-reported";
|
|
|
25
25
|
import { getPlatform } from "../platform";
|
|
26
26
|
import { mountOverviewSurface } from "../surfaces/settings-overview";
|
|
27
27
|
import { previewAssetSrcFor } from "../canvas/asset-refs";
|
|
28
|
-
import {
|
|
28
|
+
import { projectConfigPath } from "../tabs/tab";
|
|
29
29
|
|
|
30
30
|
import type {
|
|
31
31
|
OverviewActions,
|
|
@@ -191,7 +191,7 @@ function values(container: HTMLElement): OverviewValues {
|
|
|
191
191
|
error: errors.get(container) ?? null,
|
|
192
192
|
favicon: readFavicon(cfg),
|
|
193
193
|
// `project.json` authored it, whatever tab is in front: the section is project-level.
|
|
194
|
-
faviconSrc: previewAssetSrcFor(readFavicon(cfg),
|
|
194
|
+
faviconSrc: previewAssetSrcFor(readFavicon(cfg), projectConfigPath()),
|
|
195
195
|
name: cfg.name ?? "",
|
|
196
196
|
stylesDisabled: command === undefined,
|
|
197
197
|
stylesTitle: command?.title ?? "",
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from "../commands/command-args";
|
|
30
30
|
import { notify } from "../services/notify";
|
|
31
31
|
import { projectState } from "../state";
|
|
32
|
-
import {
|
|
32
|
+
import { projectConfigPath } from "../tabs/tab";
|
|
33
33
|
import { lendProjectConfigLayout } from "../tabs/project-config";
|
|
34
34
|
import { focusPane, openTab, paneOfTab, workspace } from "../workspace/workspace";
|
|
35
35
|
import { workspaceHomeTabId } from "../workspace/workspace-ids";
|
|
@@ -211,7 +211,7 @@ export function showSettingsDocument(mode: string = shell.stylebook.view): Tab |
|
|
|
211
211
|
return null;
|
|
212
212
|
}
|
|
213
213
|
rememberStylesView(mode);
|
|
214
|
-
const existing = workspace.tabs.get(
|
|
214
|
+
const existing = workspace.tabs.get(projectConfigPath());
|
|
215
215
|
if (existing) {
|
|
216
216
|
for (const candidate of PROJECT_TAB_MODES.toReversed()) {
|
|
217
217
|
if (!existing.capabilities.modes.includes(candidate)) {
|
|
@@ -225,8 +225,8 @@ export function showSettingsDocument(mode: string = shell.stylebook.view): Tab |
|
|
|
225
225
|
const tab = openTab({
|
|
226
226
|
capabilities: { modes: [...PROJECT_TAB_MODES] },
|
|
227
227
|
document: state.projectConfig ?? {},
|
|
228
|
-
documentPath:
|
|
229
|
-
id:
|
|
228
|
+
documentPath: projectConfigPath(),
|
|
229
|
+
id: projectConfigPath(),
|
|
230
230
|
});
|
|
231
231
|
/* The mode is written here rather than left to the capability list, because `createTab` seeds
|
|
232
232
|
`session.ui.canvasMode` from the first non-preview mode, and a door over the same document has
|
|
@@ -303,7 +303,7 @@ export async function openProjectSettings(section?: string): Promise<void> {
|
|
|
303
303
|
Problem rather than a toast that erases itself. */
|
|
304
304
|
notify.warn(`Could not load extension settings sections — ${errorMessage(error)}`, {
|
|
305
305
|
key: "settings:sections",
|
|
306
|
-
path:
|
|
306
|
+
path: projectConfigPath(),
|
|
307
307
|
source: "Settings",
|
|
308
308
|
tier: "problem",
|
|
309
309
|
});
|
package/src/shell.ts
CHANGED
|
@@ -102,10 +102,10 @@ export const NAVIGATOR_PANEL_IDS = [
|
|
|
102
102
|
"files",
|
|
103
103
|
"search",
|
|
104
104
|
"i18n",
|
|
105
|
+
"insert",
|
|
105
106
|
"layers",
|
|
106
107
|
"data",
|
|
107
108
|
"packages",
|
|
108
|
-
"insert",
|
|
109
109
|
] as const;
|
|
110
110
|
|
|
111
111
|
export type NavigatorPanelId = (typeof NAVIGATOR_PANEL_IDS)[number];
|