@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.
Files changed (398) hide show
  1. package/data/css-meta.json +28 -27
  2. package/dist/chunks/{cf-account-picker-h4dab9bq.js → cf-account-picker-3f08rry6.js} +21 -18
  3. package/dist/chunks/{cf-settings-adg74qsk.js → cf-settings-m79r7p5y.js} +4 -4
  4. package/dist/chunks/{components-5y78e05d.js → components-xm826zjw.js} +3 -3
  5. package/dist/chunks/{content-source-sgg1sv6n.js → content-source-jt7rbcbc.js} +22 -22
  6. package/dist/chunks/{convert-to-repeater-mf1cxgfn.js → convert-to-repeater-vg38bq99.js} +22 -22
  7. package/dist/chunks/{editor-3qhbg51x.js → editor-ddy019sn.js} +2 -2
  8. package/dist/chunks/entry-commands-64nb2a9a.js +42 -0
  9. package/dist/chunks/{extension-sections-c6zwzbre.js → extension-sections-r73an5s6.js} +31 -30
  10. package/dist/chunks/{file-ops-vrpq1jjk.js → file-ops-3xan8mnj.js} +21 -21
  11. package/dist/chunks/{files-msaf95y6.js → files-egsb0ry8.js} +30 -29
  12. package/dist/chunks/{format-host-f64fnesp.js → format-host-mym8qnd0.js} +3 -3
  13. package/dist/chunks/{fs-events-3y6y0nrm.js → fs-events-z2gg8qjt.js} +4 -4
  14. package/dist/chunks/{git-panel-bv5e22j0.js → git-panel-a05atk6q.js} +20 -20
  15. package/dist/chunks/{grid-view-1p6hsyjx.css → grid-view-3g1h2re8.css} +956 -139
  16. package/dist/chunks/{grid-view-paj67nr5.js → grid-view-qaqer9kr.js} +24 -24
  17. package/dist/chunks/{icons-yy10wk9r.js → icons-drxq9q10.js} +8 -2
  18. package/dist/chunks/{iframe-host-dh5np8vk.js → iframe-host-psetcv20.js} +11 -11
  19. package/dist/chunks/{index-n4j7qxyr.js → index-9yjae3hz.js} +4 -4
  20. package/dist/chunks/{javascript-4abzjcy9.css → javascript-bc9z461d.css} +688 -54
  21. package/dist/chunks/{javascript-xvrfrpkb.js → javascript-hr5sg57n.js} +2 -2
  22. package/dist/chunks/{jsonMode-vvmpmk34.css → jsonMode-qqd9nm1t.css} +1120 -303
  23. package/dist/chunks/{jsonMode-tyx2kj6p.js → jsonMode-zs88v0wr.js} +4 -4
  24. package/dist/chunks/{jx-validate-j0wxk72w.js → jx-validate-epp2z3s3.js} +2 -2
  25. package/dist/chunks/layers-panel-83a16ytx.js +41 -0
  26. package/dist/chunks/{layers-1vcfdbet.js → layers-s6mc01ry.js} +3 -3
  27. package/dist/chunks/{listbox-6v2ac08j.js → listbox-b7jxnhq1.js} +19 -3
  28. package/dist/chunks/{media-picker-p49nhqhs.js → media-picker-nhn6rv4w.js} +11 -11
  29. package/dist/chunks/{menu-qht48vnc.js → menu-8j4qxjrp.js} +4 -4
  30. package/dist/chunks/{monaco-binding-sw6en4dw.js → monaco-binding-e8d9wzyk.js} +3 -3
  31. package/dist/chunks/{monaco-buffer-pykwbm92.js → monaco-buffer-jaq1t9zj.js} +2 -2
  32. package/dist/chunks/{monaco-setup-8vbyqnhr.css → monaco-setup-ey9cjcm3.css} +954 -137
  33. package/dist/chunks/{monaco-setup-8r62fj6y.js → monaco-setup-gsjdysze.js} +7 -7
  34. package/dist/chunks/{platform-ts9cg1a4.js → platform-fnchmhy7.js} +5 -3
  35. package/dist/chunks/publish-panel-ak6hxfma.js +27 -0
  36. package/dist/chunks/quick-search-c63mkt3b.js +47 -0
  37. package/dist/chunks/{references-h69xp9zz.js → references-f7bdv3z5.js} +3 -3
  38. package/dist/chunks/right-panel-t5n8wttg.js +45 -0
  39. package/dist/chunks/{split-g7nm1rgb.js → split-4cz4b6ef.js} +14 -3
  40. package/dist/chunks/{studio-sar8g54p.js → studio-01269reb.js} +8 -8
  41. package/dist/chunks/{studio-rnyf3f8e.js → studio-0a4gncx0.js} +3 -3
  42. package/dist/chunks/{studio-e1f24eff.js → studio-0d4p4wxj.js} +6778 -2993
  43. package/dist/chunks/{studio-4wbb9ct0.js → studio-1tejxvba.js} +3006 -1855
  44. package/dist/chunks/{studio-p6pmwkvh.js → studio-3nprwbd9.js} +147 -28
  45. package/dist/chunks/{studio-4c041r8y.js → studio-40z39dme.js} +3 -3
  46. package/dist/chunks/{studio-68fydsrj.js → studio-482eeazk.js} +20 -20
  47. package/dist/chunks/{studio-y4f9fdge.js → studio-4998spet.js} +10 -9
  48. package/dist/chunks/{studio-nq5yf5mp.js → studio-557bmn0x.js} +2 -2
  49. package/dist/chunks/{studio-hdc2jt3z.js → studio-5w26wza5.js} +3 -3
  50. package/dist/chunks/{studio-6nzaktvy.js → studio-6pwn9j8c.js} +6 -3
  51. package/dist/chunks/{studio-wnsyffg1.js → studio-6vg0x5fz.js} +3 -2
  52. package/dist/chunks/{studio-vn5hske5.js → studio-7d3c1m59.js} +12 -5
  53. package/dist/chunks/{studio-28vs5k2y.js → studio-9vsvz7w7.js} +7 -7
  54. package/dist/chunks/{studio-t3adrr56.js → studio-9wm0xzpf.js} +19 -19
  55. package/dist/chunks/{studio-38emantv.js → studio-a5h5j33a.js} +19 -5
  56. package/dist/chunks/{studio-ympe0n7a.js → studio-ag3z6shb.js} +10 -4
  57. package/dist/chunks/studio-aj9drheq.js +177 -0
  58. package/dist/chunks/{studio-vt0tj32j.js → studio-apv9x70c.js} +189 -130
  59. package/dist/chunks/{studio-c04nzbby.js → studio-b9q3znz8.js} +2 -2
  60. package/dist/chunks/{studio-2mdbbc76.js → studio-bh47w0cy.js} +9 -10
  61. package/dist/chunks/{studio-ez11dmdh.js → studio-dgdm6vvt.js} +264 -52
  62. package/dist/chunks/{studio-5nz00bhh.js → studio-dwdcr2e8.js} +4 -4
  63. package/dist/chunks/{studio-nqgawfks.js → studio-fbcyz234.js} +146 -139
  64. package/dist/chunks/{studio-kcgff4r0.js → studio-fgmfksz8.js} +2 -2
  65. package/dist/chunks/{studio-x72j58vw.js → studio-fqpkpq1t.js} +7 -4
  66. package/dist/chunks/{studio-15f3kxqe.js → studio-fy320dfc.js} +62 -68
  67. package/dist/chunks/{studio-zjjde71a.js → studio-gjj4bbfx.js} +2 -2
  68. package/dist/chunks/{studio-66arbpc2.js → studio-jfhxy8h3.js} +16 -15
  69. package/dist/chunks/{studio-d0300636.js → studio-ks2zzth2.js} +17 -2
  70. package/dist/chunks/{studio-c07s5ckd.js → studio-kwewmhhq.js} +4 -4
  71. package/dist/chunks/{studio-01jeck2y.js → studio-m58xn8at.js} +26 -25
  72. package/dist/chunks/{studio-mpzwze9x.js → studio-mfkh1q8d.js} +17 -17
  73. package/dist/chunks/{studio-etvx9s2g.js → studio-mrh0a92f.js} +17 -17
  74. package/dist/chunks/{studio-qa7fzxan.js → studio-mt79tn56.js} +3 -3
  75. package/dist/chunks/{studio-hhskq2mr.js → studio-ne593z1j.js} +39 -32
  76. package/dist/chunks/{studio-h4nvnjvz.js → studio-ptfcxkz5.js} +418 -232
  77. package/dist/chunks/{studio-4xmjcrg3.js → studio-qxye31h7.js} +7 -7
  78. package/dist/chunks/{studio-a1pswps3.js → studio-rav5bpmp.js} +81 -59
  79. package/dist/chunks/{studio-ncn9e189.js → studio-rwmmbrth.js} +6 -6
  80. package/dist/chunks/{studio-en82c639.js → studio-sceg8ws0.js} +8 -8
  81. package/dist/chunks/{studio-wjpgxywa.js → studio-sjas5b3a.js} +19 -13
  82. package/dist/chunks/{studio-4r14yzyy.js → studio-vd67b66d.js} +3 -3
  83. package/dist/chunks/{studio-14d9tq4d.js → studio-w475cbf9.js} +10 -10
  84. package/dist/chunks/{studio-ctm7bhx5.js → studio-w7gpcvfj.js} +9 -9
  85. package/dist/chunks/{studio-9j6sfeba.js → studio-xrbfdxgk.js} +7 -7
  86. package/dist/chunks/{studio-x10fp4tp.js → studio-y49b6mjv.js} +35 -35
  87. package/dist/chunks/{studio-5t7ena5z.js → studio-ygvr9e4q.js} +10 -10
  88. package/dist/chunks/{studio-z2smx5ce.js → studio-yxmmjy2a.js} +9 -6
  89. package/dist/chunks/{tsMode-jy4m86rv.js → tsMode-ay4c78ne.js} +4 -4
  90. package/dist/chunks/{tsMode-hnxxb73h.css → tsMode-c72wyz27.css} +954 -137
  91. package/dist/chunks/{workspace-bnw54cha.js → workspace-b9k2frks.js} +5 -5
  92. package/dist/chunks/{ws-client-ny4zc51r.js → ws-client-erze4czt.js} +356 -20
  93. package/dist/codicon.ttf +0 -0
  94. package/dist/iframe-entry.js +20 -18
  95. package/dist/studio.css +956 -139
  96. package/dist/studio.js +1511 -851
  97. package/dist/workers/editor.worker.js +196 -107
  98. package/dist/workers/json.worker.js +196 -107
  99. package/dist/workers/ts.worker.js +196 -107
  100. package/package.json +18 -17
  101. package/src/about/about-modal.ts +4 -3
  102. package/src/browse/library-commands.ts +15 -13
  103. package/src/browse/library-pane.ts +2 -2
  104. package/src/canvas/canvas-render.ts +97 -83
  105. package/src/canvas/canvas-surface.ts +2 -2
  106. package/src/canvas/canvas-utils.ts +42 -32
  107. package/src/canvas/diff-toolbar.ts +21 -2
  108. package/src/canvas/diff-view.ts +30 -6
  109. package/src/canvas/iframe-entry.ts +2 -2
  110. package/src/canvas/iframe-host.ts +5 -5
  111. package/src/canvas/iframe-interaction.ts +7 -6
  112. package/src/canvas/iframe-overlay.ts +1 -1
  113. package/src/canvas/iframe-protocol.ts +6 -5
  114. package/src/canvas/iframe-render.ts +3 -3
  115. package/src/canvas/popover-state.ts +1 -1
  116. package/src/canvas/stage-scrollbar.ts +112 -0
  117. package/src/canvas/surface-registry.ts +9 -2
  118. package/src/collab/collab-commands.ts +8 -6
  119. package/src/collab/collab-session.ts +4 -4
  120. package/src/collab/collab-state.ts +4 -4
  121. package/src/collab/presence-chips.ts +3 -3
  122. package/src/commands/app-commands.ts +7 -7
  123. package/src/commands/budget.ts +17 -16
  124. package/src/commands/command-args.ts +10 -9
  125. package/src/commands/context.ts +20 -10
  126. package/src/commands/defaults.ts +30 -29
  127. package/src/commands/levels.ts +8 -6
  128. package/src/commands/live-context.ts +12 -10
  129. package/src/commands/reference.ts +5 -5
  130. package/src/commands/registry.ts +2 -2
  131. package/src/content/draft-state.ts +9 -8
  132. package/src/content/entry-commands.ts +16 -14
  133. package/src/content/entry-editor.ts +2 -2
  134. package/src/content/entry-fields.ts +1 -1
  135. package/src/editor/context-menu.ts +4 -4
  136. package/src/editor/convert-to-component.ts +6 -5
  137. package/src/editor/inline-edit.ts +3 -3
  138. package/src/editor/shortcuts.ts +88 -20
  139. package/src/editor/slash-menu.ts +11 -10
  140. package/src/files/elements.ts +4 -5
  141. package/src/files/file-ops.ts +1 -1
  142. package/src/files/files.ts +21 -17
  143. package/src/files/serialize-document.ts +1 -1
  144. package/src/format/convert-file.ts +5 -5
  145. package/src/github/github-auth-status.ts +107 -0
  146. package/src/github/github-auth.ts +18 -82
  147. package/src/github/github-publish.ts +7 -6
  148. package/src/grid/cell-editors.ts +8 -7
  149. package/src/grid/grid-layout.ts +1 -1
  150. package/src/grid/grid-open.ts +6 -5
  151. package/src/grid/grid-panel.ts +13 -12
  152. package/src/grid/redirects-grid.ts +14 -11
  153. package/src/grid/redirects.ts +10 -5
  154. package/src/grid/sources/content-source.ts +10 -9
  155. package/src/hosting/document.ts +28 -1
  156. package/src/hosting/stage.ts +15 -4
  157. package/src/i18n/i18n-commands.ts +9 -7
  158. package/src/new-project/location-fields.ts +16 -3
  159. package/src/new-project/new-project-modal.ts +23 -7
  160. package/src/page-params.ts +6 -6
  161. package/src/panels/activity-panel.ts +11 -10
  162. package/src/panels/ai-chat/chat-view.ts +27 -14
  163. package/src/panels/ai-chat/composer.ts +10 -3
  164. package/src/panels/ai-panel.ts +87 -29
  165. package/src/panels/block-action-bar.ts +59 -33
  166. package/src/panels/bottom-dock.ts +22 -22
  167. package/src/panels/chat-panel.ts +40 -5
  168. package/src/panels/data-explorer.ts +9 -9
  169. package/src/panels/data-grid.ts +1 -1
  170. package/src/panels/editors.ts +8 -8
  171. package/src/panels/elements-panel.ts +7 -8
  172. package/src/panels/empty-state.ts +1 -1
  173. package/src/panels/events-panel.ts +13 -12
  174. package/src/panels/formula-workspace.ts +8 -5
  175. package/src/panels/frontmatter-fields.ts +4 -1
  176. package/src/panels/frontmatter-panel.ts +18 -18
  177. package/src/panels/git-panel.ts +19 -13
  178. package/src/panels/head-panel.ts +9 -10
  179. package/src/panels/i18n-panel.ts +6 -4
  180. package/src/panels/imports-panel.ts +1 -1
  181. package/src/panels/jump-bar.ts +20 -18
  182. package/src/panels/layers-panel.ts +19 -17
  183. package/src/panels/left-panel.ts +3 -3
  184. package/src/panels/navigator-panels.ts +8 -8
  185. package/src/panels/overlays.ts +1 -1
  186. package/src/panels/pane-context.ts +56 -28
  187. package/src/panels/pane-grid.ts +9 -8
  188. package/src/panels/panel-registry.ts +47 -19
  189. package/src/panels/problems-panel.ts +11 -12
  190. package/src/panels/properties-panel.ts +21 -20
  191. package/src/panels/provenance.ts +3 -3
  192. package/src/panels/quick-search.ts +15 -11
  193. package/src/panels/right-panel.ts +4 -3
  194. package/src/panels/seo-modal.ts +5 -4
  195. package/src/panels/settings-menu.ts +9 -9
  196. package/src/panels/settings-pane.ts +3 -3
  197. package/src/panels/signals-panel.ts +16 -9
  198. package/src/panels/statement-editor.ts +12 -9
  199. package/src/panels/style-panel.ts +45 -41
  200. package/src/panels/stylebook-panel.ts +0 -1
  201. package/src/panels/tab-strip.ts +26 -23
  202. package/src/platform-errors.ts +2 -2
  203. package/src/platform.ts +44 -4
  204. package/src/platforms/cloud.ts +11 -1
  205. package/src/platforms/default-platform.ts +141 -4
  206. package/src/platforms/devserver.ts +23 -3
  207. package/src/publish/deploy-checklist.ts +11 -10
  208. package/src/publish/publish-commands.ts +9 -8
  209. package/src/services/a11y-report.ts +1 -1
  210. package/src/services/ai-ask.ts +39 -16
  211. package/src/services/ai-command-tools.ts +28 -14
  212. package/src/services/ai-import-tools.ts +43 -29
  213. package/src/services/ai-project-tools.ts +20 -38
  214. package/src/services/ai-settings.ts +55 -2
  215. package/src/services/ai-tools.ts +69 -58
  216. package/src/services/ai-write-report.ts +4 -4
  217. package/src/services/ai-writes.ts +74 -55
  218. package/src/services/automation.ts +12 -12
  219. package/src/services/clock.ts +2 -1
  220. package/src/services/connection.ts +2 -2
  221. package/src/services/context-manager.ts +69 -6
  222. package/src/services/directory-picker.ts +93 -27
  223. package/src/services/document-assistant.ts +86 -17
  224. package/src/services/gated-registry.ts +4 -3
  225. package/src/services/idle.ts +5 -4
  226. package/src/services/live-surfaces.ts +2 -1
  227. package/src/services/module-preloads.ts +67 -0
  228. package/src/services/notify.ts +9 -7
  229. package/src/services/popover-report.ts +3 -3
  230. package/src/services/preview-eval.ts +1 -1
  231. package/src/services/project-adoption.ts +34 -1
  232. package/src/services/project-path.ts +53 -0
  233. package/src/services/settings/kernel.ts +13 -2
  234. package/src/services/tool-executor.ts +135 -30
  235. package/src/services/tool-outcomes.ts +143 -0
  236. package/src/settings/contexts-section.ts +8 -8
  237. package/src/settings/contributed-section.ts +6 -6
  238. package/src/settings/css-vars-editor.ts +6 -5
  239. package/src/settings/extension-commands.ts +19 -18
  240. package/src/settings/extension-sections.ts +7 -7
  241. package/src/settings/extensions-section.ts +3 -3
  242. package/src/settings/general-settings.ts +21 -18
  243. package/src/settings/preferences-accounts.ts +3 -3
  244. package/src/settings/preferences-dialog.ts +9 -8
  245. package/src/settings/preferences-sections.ts +1 -1
  246. package/src/settings/project-sections.ts +2 -2
  247. package/src/settings/section-registry.ts +7 -6
  248. package/src/settings/settings-document.ts +41 -43
  249. package/src/shell/tree.ts +29 -0
  250. package/src/shell.ts +63 -55
  251. package/src/site-context.ts +1 -1
  252. package/src/store.ts +2 -2
  253. package/src/studio.ts +52 -28
  254. package/src/style/live-preview.ts +8 -8
  255. package/src/style/project-styles.ts +8 -9
  256. package/src/style/token-ref.ts +2 -2
  257. package/src/surfaces/about.json +6 -2
  258. package/src/surfaces/add-repo.json +2 -2
  259. package/src/surfaces/add-repo.ts +2 -2
  260. package/src/surfaces/ai-chat.json +14 -6
  261. package/src/surfaces/ai-chat.ts +4 -2
  262. package/src/surfaces/ai-credentials-form.json +53 -49
  263. package/src/surfaces/ai-credentials-form.ts +18 -4
  264. package/src/surfaces/ai-managed-connect.json +4 -4
  265. package/src/surfaces/block-action-bar.json +4 -4
  266. package/src/surfaces/block-action-bar.ts +3 -3
  267. package/src/surfaces/boot-failure.json +228 -0
  268. package/src/surfaces/boot-failure.ts +156 -0
  269. package/src/surfaces/bottom-dock.json +1 -1
  270. package/src/surfaces/canvas-stage.json +9 -40
  271. package/src/surfaces/canvas-stage.ts +9 -9
  272. package/src/surfaces/cf-account-picker.json +11 -8
  273. package/src/surfaces/commandbar.ts +11 -10
  274. package/src/surfaces/convert-repeater.ts +3 -2
  275. package/src/surfaces/dialog.json +7 -1
  276. package/src/surfaces/dialog.ts +2 -2
  277. package/src/surfaces/doc-header.json +6 -13
  278. package/src/surfaces/doc-header.ts +4 -5
  279. package/src/surfaces/entry-editor.json +1 -1
  280. package/src/surfaces/entry-editor.ts +2 -1
  281. package/src/surfaces/expression-editor.json +5 -5
  282. package/src/surfaces/files-panel.json +4 -3
  283. package/src/surfaces/files-panel.ts +1 -1
  284. package/src/surfaces/formula-palette.json +10 -9
  285. package/src/surfaces/formula-palette.ts +11 -7
  286. package/src/surfaces/git-panel.json +167 -109
  287. package/src/surfaces/git-panel.ts +2 -2
  288. package/src/surfaces/github-auth.json +2 -1
  289. package/src/surfaces/github-publish.ts +3 -3
  290. package/src/surfaces/grid-open.json +1 -1
  291. package/src/surfaces/grid-panel.json +2 -2
  292. package/src/surfaces/grid-views.json +1 -1
  293. package/src/surfaces/inspector-dock.json +2 -2
  294. package/src/surfaces/jump-bar.json +1 -1
  295. package/src/surfaces/jump-bar.ts +1 -1
  296. package/src/surfaces/library-pane.ts +2 -1
  297. package/src/surfaces/logic-panel.json +7 -7
  298. package/src/surfaces/logic-panel.ts +6 -4
  299. package/src/surfaces/logic-workspace.json +2 -2
  300. package/src/surfaces/logic-workspace.ts +2 -2
  301. package/src/surfaces/media-browser.ts +3 -3
  302. package/src/surfaces/media-pane.ts +2 -1
  303. package/src/surfaces/menu.ts +5 -5
  304. package/src/surfaces/new-project.json +1 -1
  305. package/src/surfaces/palette.json +8 -7
  306. package/src/surfaces/pane-context.json +86 -57
  307. package/src/surfaces/pane-context.ts +2 -1
  308. package/src/surfaces/pane-grid.json +3 -3
  309. package/src/surfaces/panel-activity.json +2 -1
  310. package/src/surfaces/panel-deploy-checklist.json +1 -1
  311. package/src/surfaces/panel-elements.ts +2 -1
  312. package/src/surfaces/panel-i18n.ts +2 -1
  313. package/src/surfaces/panel-outline.json +1 -1
  314. package/src/surfaces/panel-outline.ts +4 -3
  315. package/src/surfaces/panel-page.json +2 -2
  316. package/src/surfaces/panel-page.ts +4 -1
  317. package/src/surfaces/panel-problems.json +4 -3
  318. package/src/surfaces/panel-problems.ts +2 -2
  319. package/src/surfaces/panel-signals.json +23 -8
  320. package/src/surfaces/panel-signals.ts +5 -1
  321. package/src/surfaces/panel-stylebook-layers.json +1 -1
  322. package/src/surfaces/panel-stylebook-layers.ts +2 -2
  323. package/src/surfaces/preferences.json +21 -8
  324. package/src/surfaces/preferences.ts +9 -1
  325. package/src/surfaces/properties-panel.json +4 -4
  326. package/src/surfaces/properties-panel.ts +2 -2
  327. package/src/surfaces/publish.json +1 -1
  328. package/src/surfaces/publish.ts +2 -1
  329. package/src/surfaces/push-plan.json +4 -3
  330. package/src/surfaces/rail.json +2 -2
  331. package/src/surfaces/rail.ts +10 -4
  332. package/src/surfaces/reference-field.json +1 -1
  333. package/src/surfaces/schema-form.json +2 -2
  334. package/src/surfaces/schema-form.ts +1 -1
  335. package/src/surfaces/seo.json +1 -1
  336. package/src/surfaces/seo.ts +2 -2
  337. package/src/surfaces/settings-contributed.ts +2 -1
  338. package/src/surfaces/settings-css-vars.json +4 -4
  339. package/src/surfaces/settings-deploy.json +4 -4
  340. package/src/surfaces/settings-deploy.ts +2 -1
  341. package/src/surfaces/settings-extensions.json +6 -6
  342. package/src/surfaces/settings-extensions.ts +6 -2
  343. package/src/surfaces/settings-locales.json +4 -4
  344. package/src/surfaces/settings-overview.ts +2 -1
  345. package/src/surfaces/settings-pane.ts +3 -2
  346. package/src/surfaces/settings-rawjson.ts +1 -1
  347. package/src/surfaces/slash-menu.ts +4 -4
  348. package/src/surfaces/statements.json +3 -3
  349. package/src/surfaces/statusbar.ts +23 -23
  350. package/src/surfaces/style-panel.json +9 -5
  351. package/src/surfaces/style-panel.ts +3 -3
  352. package/src/surfaces/tab-strip.json +2 -2
  353. package/src/surfaces/target-line.json +1 -1
  354. package/src/surfaces/target-line.ts +12 -10
  355. package/src/surfaces/welcome.json +7 -2
  356. package/src/tabs/doc-op-apply.ts +5 -5
  357. package/src/tabs/patch-ops.ts +3 -3
  358. package/src/tabs/project-config.ts +10 -10
  359. package/src/tabs/selection.ts +1 -1
  360. package/src/tabs/tab.ts +13 -14
  361. package/src/tabs/transact.ts +18 -24
  362. package/src/types.ts +27 -3
  363. package/src/ui/ai-credentials-form.ts +74 -16
  364. package/src/ui/ai-managed-connect.ts +68 -19
  365. package/src/ui/color-selector.ts +1 -1
  366. package/src/ui/expression-editor.ts +3 -3
  367. package/src/ui/form-controls.ts +6 -5
  368. package/src/ui/formula-catalog.ts +4 -4
  369. package/src/ui/formula-chips.ts +2 -2
  370. package/src/ui/layers.ts +20 -18
  371. package/src/ui/panel-resize.ts +8 -28
  372. package/src/ui/popover-surface.ts +2 -2
  373. package/src/ui/progress-modal.ts +3 -3
  374. package/src/ui/regions.ts +14 -9
  375. package/src/ui/schema-form.ts +10 -9
  376. package/src/ui/timing.ts +9 -7
  377. package/src/ui/value-source.ts +4 -4
  378. package/src/ui/virtual-window.ts +58 -5
  379. package/src/utils/base64.ts +20 -1
  380. package/src/utils/canvas-media.ts +1 -1
  381. package/src/utils/studio-utils.ts +0 -31
  382. package/src/view.ts +4 -3
  383. package/src/workspace/pane-derive.ts +14 -13
  384. package/src/workspace/session.ts +7 -6
  385. package/src/workspace/workspace.ts +49 -39
  386. package/styles/canvas.css +1 -27
  387. package/styles/inspector.css +4 -3
  388. package/styles/overlays.css +1 -1
  389. package/styles/tokens.css +17 -1
  390. package/styles/tokens.json +6 -1
  391. package/dist/chunks/entry-commands-w9qsxa6q.js +0 -42
  392. package/dist/chunks/layers-panel-fksbdg4q.js +0 -40
  393. package/dist/chunks/publish-panel-vz23wwmg.js +0 -27
  394. package/dist/chunks/quick-search-e9rp74m8.js +0 -46
  395. package/dist/chunks/right-panel-j97t2yvy.js +0 -45
  396. package/dist/chunks/studio-727xh0e3.js +0 -76
  397. package/src/files/json-layout.ts +0 -474
  398. package/src/services/ai-turn-signal.ts +0 -70
@@ -37,7 +37,7 @@ import { PROJECT_CONFIG_PATH } from "../tabs/tab";
37
37
  import type { TransactOrigin } from "../tabs/transact";
38
38
  import type { TransactionRecord } from "../tabs/patch-ops";
39
39
  import type { Tab } from "../tabs/tab";
40
- import type { JxDocOp } from "@jxsuite/collab/ops";
40
+ import type { JxDocOp } from "@jxsuite/schema/doc-ops";
41
41
  import type { CollabHandle } from "@jxsuite/collab/provider";
42
42
  import type { JxMutableNode } from "@jxsuite/schema/types";
43
43
  import type * as CollabNS from "@jxsuite/collab";
@@ -664,7 +664,7 @@ export function ensureCollab(tab: Tab): void {
664
664
 
665
665
  /**
666
666
  * Join or leave this document's collaboration session — the idempotent setter behind `Collaborate:
667
- * Share this document` and `Collaborate: Stop sharing` (§7.4).
667
+ * Share this document` and `Collaborate: Stop sharing` (collab.md §4).
668
668
  *
669
669
  * Leaving sets a flag the watcher effect reads rather than calling `detachSession` directly, so the
670
670
  * effect remains the one owner of the session lifecycle and re-joining is the same call with the
@@ -709,7 +709,7 @@ async function attachSession(tab: Tab): Promise<void> {
709
709
  const platform = maybePlatform();
710
710
  if (!path || !platform?.collab) {
711
711
  /* Not a failure and not a session: this build/platform has no collaboration to offer. Saying
712
- so is the difference between "nobody else is here" and "something broke" (§7.4). */
712
+ so is the difference between "nobody else is here" and "something broke" (collab.md §4). */
713
713
  collabState(tab).status = "unavailable";
714
714
  return;
715
715
  }
@@ -753,7 +753,7 @@ async function attachSession(tab: Tab): Promise<void> {
753
753
  } catch (error) {
754
754
  /* An attach that threw is a FAILURE, and it used to be reported as "detached" — the same
755
755
  value a solo document carries. A relay that is down, a token that expired and a document
756
- nobody shared were one indistinguishable state (§7.4). */
756
+ nobody shared were one indistinguishable state (collab.md §4). */
757
757
  state.status = "failed";
758
758
  state.active = false;
759
759
  state.attachError = error instanceof Error ? error.message : String(error);
@@ -13,9 +13,9 @@ import type { CollabAwarenessState } from "@jxsuite/collab/awareness-types";
13
13
  *
14
14
  * `"detached"` used to mean three different things at once and say none of them: this build has no
15
15
  * collaboration at all, this project has collaboration but this tab is solo, and the attach was
16
- * tried and it FAILED. §7.4: a freeze is currently indistinguishable from a bug, and so was a
17
- * broken connection. `"unavailable"` and `"failed"` split the third and first cases out, so the
18
- * chip can say which one it is.
16
+ * tried and it FAILED. A freeze was indistinguishable from a bug, and so was a broken connection
17
+ * (collab.md §4). `"unavailable"` and `"failed"` split the third and first cases out, so the chip
18
+ * can say which one it is.
19
19
  */
20
20
  export type CollabTabStatus =
21
21
  | "unavailable"
@@ -42,7 +42,7 @@ export interface TabCollabState {
42
42
  * surfaces soft-freeze and the canvas previews the source reconciler's parses.
43
43
  *
44
44
  * The freeze is real and it is brief, and until now its only rendering was a grey line for three
45
- * seconds — which is exactly what a bug looks like. It gets an indicator (§7.4).
45
+ * seconds — which is exactly what a bug looks like. It gets an indicator (collab.md §4).
46
46
  */
47
47
  sourceCanonical: boolean;
48
48
  /**
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Presence chips — who else is in this co-editing session, the sync-status pill that replaces the
3
- * dirty dot for collab tabs, and the two states co-editing had no way to announce (§7.4).
3
+ * dirty dot for collab tabs, and the two states co-editing had no way to announce (collab.md §4).
4
4
  *
5
5
  * Pure projections of `collabState(tab)`: the Command Bar surface draws the cluster and the pane's
6
6
  * own chrome draws the banner, and both are documents, so nothing here renders.
@@ -22,8 +22,8 @@
22
22
  *
23
23
  * **Undo says what it does.** The Y.UndoManager is constructed with `trackedOrigins:
24
24
  * {LOCAL_ORIGIN}`, so ⌘Z reaches your own actions and never a peer's. That is the correct behaviour
25
- * and it is also surprising, so the status pill's title states it — §13 lists this as adopted
26
- * precisely because silently undoing someone else's work is worse than not undoing.
25
+ * and it is also surprising, so the status pill's title states it (collab.md §4). The scoping is
26
+ * deliberate: silently undoing someone else's work is worse than not undoing.
27
27
  */
28
28
 
29
29
  import { collabState } from "./collab-state";
@@ -8,12 +8,12 @@
8
8
  * process with no DOM and no bootstrap, and each looks for one export — `defaultCommandSet()`.
9
9
  *
10
10
  * Without this module those three checks see only `commands/defaults.ts`'s sixteen records, which
11
- * is why plan §13.5's headline promise was not yet true: a manifest step naming `view.setActivity`
12
- * with a panel id the registry does not declare sailed through Lane 1, because Lane 1 could not
13
- * load the record that declares the enum. Every module gathered below imports cleanly with no
14
- * `document` and no `localStorage` write, which is the ONLY property this file requires of them —
15
- * and the test beside it asserts exactly that, so a future DOM read at module scope fails here
16
- * rather than in CI.
11
+ * is why the screenshot gate's headline promise (`scripts/screenshots/README.md`, "The gate") was
12
+ * not yet true: a manifest step naming `view.setActivity` with a panel id the registry does not
13
+ * declare sailed through Lane 1, because Lane 1 could not load the record that declares the enum.
14
+ * Every module gathered below imports cleanly with no `document` and no `localStorage` write, which
15
+ * is the ONLY property this file requires of them — and the test beside it asserts exactly that, so
16
+ * a future DOM read at module scope fails here rather than in CI.
17
17
  *
18
18
  * **Deps are the no-op set.** Nothing here runs a command; the checks read `id`, `level`, `menus`
19
19
  * and `args`. Passing real implementations would mean importing the app.
@@ -136,7 +136,7 @@ export function appCommandSet(): AnyCommand[] {
136
136
  // And none reached the palette, because they were registered ONLY into the private registry
137
137
  // `editor/context-menu.ts` builds for its popover — a registry whose own docstring said it
138
138
  // Existed "until a bootstrap composes every contribution point into a single app-wide
139
- // Registry". This is that bootstrap; it has existed since P2.
139
+ // Registry". This is that bootstrap; it has existed since the command registry landed.
140
140
  ...liveElementCommands(),
141
141
  ...dataExplorerCommands({ renderLeftPanel: NO_OP }),
142
142
  ...signalsCommands(),
@@ -1,26 +1,27 @@
1
1
  /**
2
2
  * Budget.ts — chrome is earned by frequency and capped by a build check.
3
3
  *
4
- * Plan §2, principle 9: at most five commands may declare `menus: ["commandbar/primary"]`, and at
5
- * most four tabs per dock. `scripts/check-chrome-budget.ts` fails CI otherwise, which is what turns
6
- * "we should keep the toolbar small" from a code-review opinion into a build error.
4
+ * The chrome budget, studio-ui-guidelines.md §12.2: at most five commands may declare `menus:
5
+ * ["commandbar/primary"]`, and at most four tabs per dock. `scripts/check-chrome-budget.ts` fails
6
+ * CI otherwise, which is what turns "we should keep the toolbar small" from a code-review opinion
7
+ * into a build error.
7
8
  *
8
9
  * The cap is not arbitrary. The toolbar's own CSS already admits it is over budget — a container
9
10
  * query at 1140px strips every `.tb-label` rather than conceding there are too many controls — and
10
11
  * an unlabelled icon is a control the user has to hover to identify. A hard number is what makes
11
12
  * "retire this control, keep its name and its chord" the cheap option.
12
13
  *
13
- * The dock/tab sets used to be a flat declaration — written out from §3.2 because `registerPanel()`
14
- * did not exist. It does now, so the two `rail/*` rows are a QUERY over `railDeclarations()`
15
- * ({@link dockTabs}) and adding a ninth rail panel fails this check without anyone remembering to
16
- * update a list. The two rows that remain declared are the two docks whose tab sets this module
17
- * cannot see from a bare Bun process: the Inspector's four come from `commands/defaults.ts`'s
18
- * `INSPECTOR_TABS` (a query in all but name), and the Bottom dock's four are records in
19
- * `panels/bottom-dock.ts`, which renders lit templates and therefore cannot be imported here.
20
- * `tests/bottom-dock.test.ts` asserts the declared row and the registered set are the same four
21
- * titles, so the copy cannot drift — the same bargain `tests/right-panel.test.ts` strikes for the
22
- * Inspector. Both become real queries the day `scripts/check-chrome-budget.ts` joins them the way
23
- * it already joins the rail.
14
+ * The dock/tab sets used to be a flat declaration — written out by hand from the shell redesign's
15
+ * region table, because `registerPanel()` did not exist. It does now, so the two `rail/*` rows are
16
+ * a QUERY over `railDeclarations()` ({@link dockTabs}) and adding a ninth rail panel fails this
17
+ * check without anyone remembering to update a list. The two rows that remain declared are the two
18
+ * docks whose tab sets this module cannot see from a bare Bun process: the Inspector's four come
19
+ * from `commands/defaults.ts`'s `INSPECTOR_TABS` (a query in all but name), and the Bottom dock's
20
+ * four are records in `panels/bottom-dock.ts`, which renders lit templates and therefore cannot be
21
+ * imported here. `tests/bottom-dock.test.ts` asserts the declared row and the registered set are
22
+ * the same four titles, so the copy cannot drift — the same bargain `tests/right-panel.test.ts`
23
+ * strikes for the Inspector. Both become real queries the day `scripts/check-chrome-budget.ts`
24
+ * joins them the way it already joins the rail.
24
25
  */
25
26
 
26
27
  import { INSPECTOR_TABS } from "./defaults";
@@ -46,7 +47,7 @@ export const CHROME_BUDGET = {
46
47
  *
47
48
  * A prompt is chrome for a model: every tool costs attention, and issue 273's finding was that a
48
49
  * naive projection of every declaration would have taken the list from 22 to 67. Thirty is
49
- * headroom over today's 28 (19 hand + 9 projected), not a target. Asserted in
50
+ * headroom over today's 29 (18 hand + 11 projected), not a target. Asserted in
50
51
  * `tests/ai-command-tools.test.ts` rather than `scripts/check-chrome-budget.ts`, because the hand
51
52
  * table lives in `ai-system-prompt.ts`, which imports `../store.js` and is not bare-Bun loadable;
52
53
  * the number lives here either way, and raising it is a design decision.
@@ -56,7 +57,7 @@ export const CHROME_BUDGET = {
56
57
 
57
58
  /** One tabbed region and what it currently hosts. */
58
59
  export interface DockDeclaration {
59
- /** Region key as §3.2 names it. Rail groups count separately — they are separate placements. */
60
+ /** Region key. Rail groups count separately — they are separate placements. */
60
61
  dock: string;
61
62
  tabs: readonly string[];
62
63
  }
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Command-args.ts — loud coercion for the arguments a command record declares.
3
3
  *
4
- * Every scriptable command carries an `args` JSON Schema (spec §13.1, plan §13.3): the palette
5
- * prompts from it, the AI tool's parameters are it, and `scripts/check-shot-contract.ts` validates
6
- * every manifest step against it in the `checks` job. This module is the RUNTIME half of that same
4
+ * Every scriptable command carries an `args` JSON Schema (studio.md §13.1): the palette prompts
5
+ * from it, the AI tool's parameters are it, and `scripts/check-shot-contract.ts` validates every
6
+ * manifest step against it in the `checks` job. This module is the RUNTIME half of that same
7
7
  * declaration, twice over: the typed readers a `run` body calls (`stringArg(...)` and its family),
8
8
  * and {@link coerceArgs}, which `registry.run` applies to the received record BEFORE `run` for
9
9
  * every caller — the palette, `__jxAutomation`, the assistant and a chord alike. The coercion
@@ -16,11 +16,12 @@
16
16
  * 1. **Reject loudly, never clamp.** An unknown panel id, a mode the tab cannot enter, a selection
17
17
  * path that is not in the document — each throws. A no-op would photograph the previous state
18
18
  * and a docs build would accept it; a clamp would photograph a state the caller did not ask for.
19
- * Plan §13.4 makes this a tested property.
19
+ * The shot contract (`scripts/screenshots/README.md`, `steps`) makes this a tested property.
20
20
  * 2. **The failure names the fix.** `{@link enumArg}` prints the declared values, which is what makes
21
- * §13.5's headline failure — _manifest shot "properties-bar" names panel "head"; the registry
22
- * declares "page"_ — a sentence a reader can act on rather than a stack trace. Nothing else in
23
- * this file matters as much as that message.
21
+ * the screenshot gate's headline failure (`scripts/screenshots/README.md`, "The gate") —
22
+ * _manifest shot "properties-bar" names panel "head"; the registry declares "page"_ — a sentence
23
+ * a reader can act on rather than a stack trace. Nothing else in this file matters as much as
24
+ * that message.
24
25
  *
25
26
  * `RangeError` (not a bespoke class) because `services/profile.ts` already throws it for exactly
26
27
  * this — an id outside a declared set — and one refusal shape is easier to catch than two.
@@ -185,7 +186,7 @@ export function nullablePathArg(
185
186
  }
186
187
 
187
188
  /**
188
- * A LIST of document paths — the whole selection set (§6.5).
189
+ * A LIST of document paths — the whole selection set (§6.7).
189
190
  *
190
191
  * Every element is validated as a path, so a caller that passes one bare path by mistake
191
192
  * (`["children", 0]` rather than `[["children", 0]]`) is refused by name instead of selecting two
@@ -218,7 +219,7 @@ export function pathListArg(
218
219
 
219
220
  // ─── Schema fragments ─────────────────────────────────────────────────────────
220
221
  // The readers above are what a `run` body calls; these are the same facts in the form the palette
221
- // Prompt, the AI tool's parameter list and Lane 1's static check read. The pair used to be kept
222
+ // Prompt, the AI tool's parameter list and the shot-contract check read. The pair used to be kept
222
223
  // Adjacent so a reviewer could see that a schema agreed with its coercion; `coerceArgs` below made
223
224
  // Them ONE call site, so a schema that disagrees with its coercion is now a refusal rather than a
224
225
  // Defect a reviewer has to spot — which is what this module exists to prevent.
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Context.ts — the record every `when` / `enablement` predicate closes over.
3
3
  *
4
- * One flat-ish record of the facts a command can be gated on (UX-REDESIGN-PLAN §5.2). Predicates
4
+ * One flat-ish record of the facts a command can be gated on (specs/studio.md §13.4). Predicates
5
5
  * are plain closures over this record — the shape `services/gated-registry.ts` already ships for
6
- * the AI's tools — not a serialisable string DSL. §13 rejects the DSL explicitly: a `"project.open
7
- * && editor.kind == 'canvas'"` grammar needs a tokenizer, a parser and a reactive evaluator to buy
8
- * serialisability nothing in Studio consumes.
6
+ * the AI's tools — not a serialisable string DSL, which the shell redesign rejected explicitly: a
7
+ * `"project.open && editor.kind == 'canvas'"` grammar needs a tokenizer, a parser and a reactive
8
+ * evaluator to buy serialisability nothing in Studio consumes.
9
9
  *
10
10
  * This module owns the SHAPE and a pure builder. It deliberately imports nothing from the state
11
11
  * modules: the registry takes a `getContext()` thunk, so wiring the live sources (the reactive
@@ -32,6 +32,9 @@ export const CAPABILITIES = [
32
32
  "dataRows",
33
33
  "windowControls",
34
34
  "findReferences",
35
+ /* The image editor's gate. A backend that cannot hand Studio a project file's raw bytes cannot
36
+ decode one, so the Image mode is not offered at all rather than offered and then failing. */
37
+ "readFileBytes",
35
38
  ] as const;
36
39
 
37
40
  export type Capability = (typeof CAPABILITIES)[number];
@@ -182,7 +185,7 @@ export interface CommandContext {
182
185
  selection: {
183
186
  count: number;
184
187
  /**
185
- * The selected document paths, in selection order — `[]` when nothing is selected (§6.5).
188
+ * The selected document paths, in selection order — `[]` when nothing is selected (§6.7).
186
189
  *
187
190
  * The context is what `probe.state()` answers with, so this is how a script, a screenshot step
188
191
  * or the assistant READS a multi-selection back. `count` is its length; the last entry is the
@@ -237,13 +240,19 @@ export interface CommandContext {
237
240
  };
238
241
  ai: {
239
242
  configured: boolean;
243
+ /**
244
+ * A turn is in flight: from an accepted send until its loop ends, with its tools, its questions
245
+ * and its imports included (specs/ai.md §3.0). Not the token stream, which the chat's own
246
+ * status reports and which reads idle whenever the turn's tools are running.
247
+ */
240
248
  streaming: boolean;
241
249
  /**
242
250
  * A turn is suspended on an `ask_user` question.
243
251
  *
244
- * Distinct from `streaming` rather than folded into it: no tokens are moving, so a surface that
245
- * paints a spinner on `streaming` must not paint one here — but the turn is alive and holding a
246
- * tool open, so Stop is enabled on the union of the two.
252
+ * Always inside a turn, so `streaming` holds too. Kept as its own fact for `when` predicates
253
+ * and the live-context probe: while a question waits, a send is its answer rather than a new
254
+ * turn (the composer reads the same fact straight from `panels/ai-panel.ts`). Stop's union with
255
+ * it is the same thing as `streaming`.
247
256
  */
248
257
  waiting: boolean;
249
258
  };
@@ -309,6 +318,7 @@ export function emptyContext(): CommandContext {
309
318
  dataRows: false,
310
319
  windowControls: false,
311
320
  findReferences: false,
321
+ readFileBytes: false,
312
322
  },
313
323
  };
314
324
  }
@@ -358,8 +368,8 @@ const GLOBAL_STACK: readonly KeyScope[] = ["global"];
358
368
  /**
359
369
  * The scope stack for the current context, narrowest scope first.
360
370
  *
361
- * The ladder is `caret > grid/code engine > focused dock > global` (plan §5.3), and the whole point
362
- * is that a scope which is not on the stack cannot fire AT ALL. Three hand-written guards collapse
371
+ * The ladder is `caret > grid/code engine > focused dock > global` (§13.3), and the whole point is
372
+ * that a scope which is not on the stack cannot fire AT ALL. Three hand-written guards collapse
363
373
  * into it:
364
374
  *
365
375
  * - The blanket modal return → the `palette`-only stack;
@@ -21,7 +21,8 @@
21
21
  * print — one sentence, three consumers.
22
22
  *
23
23
  * The primary Command Bar cluster is capped at five by `scripts/check-chrome-budget.ts`; four are
24
- * spent here (Save, Undo, Redo, Open in Browser) exactly as plan §3.2 region ① specifies.
24
+ * spent here (Save, Undo, Redo, Open in Browser), exactly the four studio-ui-guidelines.md §12.1
25
+ * admits to `commandbar/primary` at document level.
25
26
  */
26
27
 
27
28
  import { isSpliceablePath } from "../tabs/selection";
@@ -41,10 +42,10 @@ import type { CommandContext } from "./context";
41
42
  export type DockId = "navigator" | "inspector" | "bottom";
42
43
 
43
44
  /**
44
- * Palette modes, echoed as a removable chip in the input (plan §5.4).
45
+ * Palette modes, echoed as a removable chip in the input.
45
46
  *
46
47
  * The value space is the palette's namespace, declared once here so a new mode is a new member
47
- * rather than a new widget: P4's Problems and P7's content search slot in beside these.
48
+ * rather than a new widget: a Problems mode or a content search slots in beside these.
48
49
  */
49
50
  export type PaletteMode = "picker" | "files" | "commands" | "nodes" | "projects";
50
51
 
@@ -68,15 +69,14 @@ export interface RailPanel {
68
69
  when?: (ctx: CommandContext) => boolean;
69
70
  }
70
71
 
71
- /** How many rail panels get a ⌘N. §3.2 ② spends exactly this many slots, four per level group. */
72
+ /** How many rail panels get a ⌘N: the Navigator rail (§5.1) spends four per level group. */
72
73
  export const RAIL_CHORD_LIMIT = 8;
73
74
 
74
75
  /**
75
- * The Inspector's four tabs, in the order §3.2 ⑨ names them — which is the order ⌘⇧1–4 follow.
76
+ * The Inspector's four tabs, in the order §6 names them — which is the order ⌘⇧1–4 follow.
76
77
  *
77
- * `"assistant"` is a different dock (it is the Inspector's second instance until P3.6 folds the
78
- * column in), so it is not one of `shell.ts`'s `INSPECTOR_TAB_IDS`; the chord still belongs in the
79
- * same run of four, because a user counting tabs does not know that.
78
+ * `"assistant"` is the fourth tab, not a dock of its own (there is no assistant column, §3.1), so
79
+ * it is one of `shell.ts`'s `INSPECTOR_TAB_IDS` like the other three.
80
80
  */
81
81
  export interface InspectorTab {
82
82
  /** The stored `session.ui.rightTab` value, or `"assistant"` for the assistant dock. */
@@ -130,9 +130,9 @@ export interface CommandDeps {
130
130
  */
131
131
  panelRoster: readonly RailPanel[];
132
132
  /**
133
- * Toggle-FOCUS a panel (plan §5.3): reveal it and take focus, or — when it already has focus —
134
- * collapse the dock hosting it and hand focus back to the pane. Deliberately not toggle-visible:
135
- * ⌘1 pressed from the canvas must land you in Files, not close it.
133
+ * Toggle-FOCUS a panel: reveal it and take focus, or — when it already has focus — collapse the
134
+ * dock hosting it and hand focus back to the pane. Deliberately not toggle-visible: ⌘1 pressed
135
+ * from the canvas must land you in Files, not close it.
136
136
  */
137
137
  focusPanel: (panelId: string) => void;
138
138
  /** Show an Inspector tab and focus the dock. `"assistant"` addresses the assistant dock. */
@@ -202,11 +202,11 @@ const structurallyEditable = (ctx: CommandContext) =>
202
202
  /**
203
203
  * The one sentence for {@link structurallyEditable}, read by Delete and Duplicate both.
204
204
  *
205
- * It names the gate the predicate actually has (§12.4's corollary): the old sentences said "not the
206
- * document root" and "has a sibling position" for a gate that also refuses a repeater's template
207
- * and a `$switch` case, which sent a reader who had selected a template looking for a root. Two
208
- * records with one predicate carry one sentence, because the tooltip, the palette subtitle and the
209
- * assistant's refusal are all this string.
205
+ * It names the gate the predicate actually has (studio-ui-guidelines.md §12.4's corollary): the old
206
+ * sentences said "not the document root" and "has a sibling position" for a gate that also refuses
207
+ * a repeater's template and a `$switch` case, which sent a reader who had selected a template
208
+ * looking for a root. Two records with one predicate carry one sentence, because the tooltip, the
209
+ * palette subtitle and the assistant's refusal are all this string.
210
210
  */
211
211
  const SPLICEABLE_SELECTION =
212
212
  "an element selected on the canvas that has a sibling position: not the document root, a " +
@@ -278,7 +278,7 @@ export function defaultCommands(deps: CommandDeps): AnyCommand[] {
278
278
  * the build keeps a command of its own rather than disappearing with the coupling.
279
279
  *
280
280
  * `commandbar/overflow` rather than `commandbar/primary`: the primary row is budgeted at five
281
- * and is document-level by frequency (studio-ui-guidelines §12), and a build is neither
281
+ * and is document-level by frequency (studio-ui-guidelines.md §12), and a build is neither
282
282
  * frequent nor about the document in front of you. No default chord for the same reason.
283
283
  */
284
284
  id: "project.buildSite",
@@ -373,10 +373,11 @@ export function defaultCommands(deps: CommandDeps): AnyCommand[] {
373
373
  enablement: (ctx) => structurallyEditable(ctx) && !ctx.selection.isRepeater,
374
374
  requires: "an element with a sibling position that is not already a repeater",
375
375
  /*
376
- * No `aiTool`, by §12.4's second deletion rule: `run` waits on a person. The dialog picks the
377
- * collection, and a projected call would suspend the agent's turn on it while the loop counts
378
- * the round as work; a cancel returns nothing a report could describe. A record with a
379
- * `collection` argument that skips the dialog would be the way back in, and is a UX call.
376
+ * No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: `run` waits on a
377
+ * person. The dialog picks the collection, and a projected call would suspend the agent's
378
+ * turn on it while the loop counts the round as work; a cancel returns nothing a report could
379
+ * describe. A record with a `collection` argument that skips the dialog would be the way back
380
+ * in, and is a UX call.
380
381
  *
381
382
  * The one record here whose implementation is not injected, and the reason is a property of
382
383
  * the implementation rather than of this record: `convertToRepeater()` is self-contained —
@@ -540,11 +541,11 @@ export function defaultCommands(deps: CommandDeps): AnyCommand[] {
540
541
  /*
541
542
  * The other half of multi-window, and the half that had no door.
542
543
  *
543
- * "Open a project ELSEWHERE" is reachable from Open Project and from Recents (§4.2a); "open
544
- * an EMPTY window" was reachable only from the ElectroBun launcher's native application menu
545
- * — so on a launcher whose window has no menu bar, `newWindow` existed on the platform and
546
- * could not be run. Gated on the same capability every other multi-window verb is, so a host
547
- * with one window does not offer it.
544
+ * "Open a project ELSEWHERE" is reachable from Open Project and from Recents
545
+ * (desktop.md §4.2a); "open an EMPTY window" was reachable only from the ElectroBun
546
+ * launcher's native application menu — so on a launcher whose window has no menu bar,
547
+ * `newWindow` existed on the platform and could not be run. Gated on the same capability
548
+ * every other multi-window verb is, so a host with one window does not offer it.
548
549
  */
549
550
  id: "view.newWindow",
550
551
  title: "New Window",
@@ -559,7 +560,7 @@ export function defaultCommands(deps: CommandDeps): AnyCommand[] {
559
560
  },
560
561
  {
561
562
  // The no-project palette stops being a hidden domain swap on `!projectState` and becomes a
562
- // NAMED mode that works either way (plan §5.4) — same trigger, same chrome, stated feature.
563
+ // NAMED mode that works either way — same trigger, same chrome, stated feature.
563
564
  id: "project.openRecent",
564
565
  title: "Open Recent…",
565
566
  category: "Project",
@@ -569,7 +570,7 @@ export function defaultCommands(deps: CommandDeps): AnyCommand[] {
569
570
  run: () => deps.openPalette("projects"),
570
571
  },
571
572
 
572
- // ── Direct keys (plan §5.3) ──
573
+ // ── Direct keys ──
573
574
  ...panelFocusCommands(deps),
574
575
  ...inspectorFocusCommands(deps),
575
576
  {
@@ -602,7 +603,7 @@ export function defaultCommands(deps: CommandDeps): AnyCommand[] {
602
603
  * Generated rather than written out eight times for the reason the whole registry exists: the rail,
603
604
  * the chord, the palette row and the generated shortcut sheet are then four renderings of one list.
604
605
  * Only the first eight get a chord; a ninth panel keeps its name and its palette row, which is the
605
- * cost §2 principle 9 puts on chrome.
606
+ * cost studio-ui-guidelines.md §12.2 puts on chrome.
606
607
  */
607
608
  export function panelFocusCommands(deps: CommandDeps): AnyCommand[] {
608
609
  let chordsSpent = 0;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Levels.ts — the containment taxonomy and the level × placement matrix.
3
3
  *
4
- * Two vocabularies live here, and keeping them apart is the whole point (UX-REDESIGN-PLAN §5.1):
4
+ * Two vocabularies live here, and keeping them apart is the whole point (specs/studio.md
5
+ * §13.2–§13.3):
5
6
  *
6
7
  * - {@link Level} answers WHAT a record acts on. It governs placement and is CI-checked.
7
8
  * - {@link KeyScope} answers WHERE a chord is live. It governs keyboard dispatch only.
@@ -150,9 +151,10 @@ export const PLACEMENT_MATRIX: Readonly<Record<Placement, PlacementRule>> = {
150
151
  /**
151
152
  * Every surface a Panel record may occupy.
152
153
  *
153
- * The rail's two level groups are SEPARATE placements, not one "mixed" region — principle 2's whole
154
- * point. `navigator` is the dock body below them, which hosts whichever panel the rail selected and
155
- * prints that panel's level in its header, so it is the one panel placement admitting two levels.
154
+ * The rail's two level groups are SEPARATE placements, not one "mixed" region — the whole point of
155
+ * the level × placement matrix (studio-ui-guidelines.md §12.1). `navigator` is the dock body below
156
+ * them, which hosts whichever panel the rail selected and prints that panel's level in its header,
157
+ * so it is the one panel placement admitting two levels.
156
158
  */
157
159
  export const PANEL_PLACEMENTS = [
158
160
  "rail/project",
@@ -169,7 +171,7 @@ export type PanelPlacement = (typeof PANEL_PLACEMENTS)[number];
169
171
  * `studio-ui-guidelines.md` §12 beside {@link PLACEMENT_MATRIX}.
170
172
  *
171
173
  * The rail rows are what stop it re-accreting: a panel cannot be filed in the PROJECT group because
172
- * "it feels project-ish", only because the state it WRITES is the project's (principle 3).
174
+ * "it feels project-ish", only because the state it WRITES is the project's (§13.2).
173
175
  */
174
176
  export const PANEL_PLACEMENT_MATRIX: Readonly<Record<PanelPlacement, PlacementRule>> = {
175
177
  "rail/project": {
@@ -215,7 +217,7 @@ function dockPlacement(dock: PlaceablePanel["dock"]): PanelPlacement {
215
217
  * Every placement a Panel record occupies: its dock body, plus its rail group when it has a button.
216
218
  *
217
219
  * The rail group is DERIVED from the level rather than declared, which is what makes "grouped by
218
- * level with a divider" (§3.2 ②) a property of the data instead of an ordering convention in the
220
+ * level with a divider" (§5.1) a property of the data instead of an ordering convention in the
219
221
  * rail's template. A rail panel whose level has no group (`application`, `selection`) therefore
220
222
  * names a placement the matrix does not contain, and is rejected below.
221
223
  */
@@ -65,7 +65,7 @@ export function isTextEntryFocused(doc: Document = document): boolean {
65
65
  export interface LiveContextSources {
66
66
  /** `studio.ts`'s `getCanvasMode()` — the per-tab preview toggle already composed in. */
67
67
  canvasMode: () => string;
68
- /** `canvas/iframe-host.ts`'s bridge-derived caret flag (P1). */
68
+ /** `canvas/iframe-host.ts`'s bridge-derived caret flag (§10). */
69
69
  isCaretActive: () => boolean;
70
70
  /** `ui/layers.ts`'s `isModalOpen()`. */
71
71
  isModalOpen: () => boolean;
@@ -74,8 +74,9 @@ export interface LiveContextSources {
74
74
  /** Whether the assistant has usable credentials (`services/ai-models`). */
75
75
  aiConfigured: () => boolean;
76
76
  /**
77
- * Whether the assistant is mid-stream. `panels/ai-panel.ts` keeps its `DocumentAssistant` module-
78
- * private, so there is nothing to read yet; the caller passes a probe when one exists.
77
+ * Whether an assistant turn is in flight, tools and questions included. `panels/ai-panel.ts`
78
+ * keeps its `DocumentAssistant` module-private, so the caller passes its probe
79
+ * (`isAssistantStreaming`).
79
80
  */
80
81
  aiStreaming?: () => boolean;
81
82
  /** Whether a turn is suspended on an `ask_user` question (`panels/ai-panel.ts`). */
@@ -93,6 +94,7 @@ function capabilities(platform: StudioPlatform | null): CommandContext["capabili
93
94
  gitClone: has("gitClone"),
94
95
  importSite: has("importSite"),
95
96
  openProjectInNewWindow: has("openProjectInNewWindow"),
97
+ readFileBytes: has("readFileBytes"),
96
98
  // Multi-window is a desktop-only family; `newWindow` is the one every member implies.
97
99
  windowControls: has("newWindow"),
98
100
  };
@@ -138,13 +140,13 @@ export function createLiveContext(sources: LiveContextSources): () => CommandCon
138
140
 
139
141
  ctx.editor.kind = tab ? editorKindForMode(mode) : "none";
140
142
  ctx.canvas.view = canvasViewForMode(mode);
141
- /* The grid, counted from the grid. This read spent two phases saying "panes land in P3; until
142
- then the grid is one pane showing the focused tab" — through P3, which built the pane model,
143
- and through P8, which gave every pane a live stage. It counted `workspace.tabOrder`, the
144
- FOCUSED pane's strip, so it could never answer 2 and answered 0 whenever no tab was open,
145
- while a pane with no tab is still a pane. `derived` was declared and never assigned at all.
146
- `services/automation.ts` publishes this whole record as `probe.state()`, so the screenshot
147
- pipeline and the assistant were both reading it.
143
+ /* The grid, counted from the grid. This read spent two phases saying that until panes landed
144
+ the grid was one pane showing the focused tab — through the shell redesign's chrome phase,
145
+ which built the pane model, and through its panes phase, which gave every pane a live stage.
146
+ It counted `workspace.tabOrder`, the FOCUSED pane's strip, so it could never answer 2 and
147
+ answered 0 whenever no tab was open, while a pane with no tab is still a pane. `derived` was
148
+ declared and never assigned at all. `services/automation.ts` publishes this whole record as
149
+ `probe.state()`, so the screenshot pipeline and the assistant were both reading it.
148
150
 
149
151
  `derived` is ASSIGNED now, and it means "the grid contains a derived pane" — the fact the two
150
152
  predicates that need it actually ask. A third phase of a declared-never-assigned context key
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Reference.ts — the registry, projected into the two generated documentation pages.
3
3
  *
4
- * Plan §12 P3 lists `docs/studio/interface/shortcuts.md` and a new
5
- * `docs/studio/interface/commands.md` as **generated from the registry at build time**, which is
6
- * the last of §5.5's seven derivations: with the chrome, the keymap, the palette, the menus and the
7
- * automation surface all rendering the same records, a hand-maintained shortcut sheet is the only
8
- * place left for the app's keyboard and its documentation to disagree.
4
+ * `docs/studio/interface/shortcuts.md` and `docs/studio/interface/commands.md` are **generated from
5
+ * the registry at build time**, the last of the renderings §13 derives from it: with the chrome,
6
+ * the keymap, the palette, the menus and the automation surface all rendering the same records, a
7
+ * hand-maintained shortcut sheet is the only place left for the app's keyboard and its
8
+ * documentation to disagree.
9
9
  *
10
10
  * This module is the projection, not the generator. It takes a command set — `appCommandSet()`, the
11
11
  * one bare-Bun-importable export the three CI checks already load — and returns ROWS plus the
@@ -6,7 +6,7 @@
6
6
  * default chord, and the surfaces it belongs in. Every surface — Command Bar, palette, rail,
7
7
  * context menus, the block action bar, the keymap, `__jxAutomation` and the assistant's tools —
8
8
  * becomes a RENDERING of these records. A surface may choose whether to show a command; it may
9
- * never decide what it is called, when it is available, or what it does (plan §2, principle 1).
9
+ * never decide what it is called, when it is available, or what it does (§13).
10
10
  *
11
11
  * Four things fail loudly at registration rather than degrading into a surface disagreement:
12
12
  *
@@ -23,7 +23,7 @@
23
23
  * `when` / `enablement` are `(ctx) => boolean` closures, modelled on the shipped
24
24
  * `services/gated-registry.ts` `ToolAvailability`, and `requires` is ONE string with three
25
25
  * consumers: the disabled control's tooltip, the palette row's grey subtitle and the agent's
26
- * refusal message. Plan §13 rejects a serialisable string DSL; do not add one.
26
+ * refusal message. §13.1 rejects a serialisable string DSL; do not add one.
27
27
  *
28
28
  * The registry takes its context by injection (`getContext`), so nothing here imports a state
29
29
  * module. That is what lets the CI checks import the command set in a bare Bun process and lets
@@ -1,5 +1,6 @@
1
1
  /**
2
- * The draft axis (§7.6) — what a draft IS, and whether drafts are listed. One place, every list.
2
+ * The draft axis (site-architecture.md §7.6) — what a draft IS, and whether drafts are listed. One
3
+ * place, every list.
3
4
  *
4
5
  * It is deliberately its own module rather than a field on a pane's state and rather than a section
5
6
  * of `entry-model.ts`. Two reasons, and the second is why the definitions live here beside the
@@ -20,17 +21,17 @@
20
21
  import { reactive } from "../reactivity";
21
22
  import type { ContentTypeSchema } from "@jxsuite/schema/types";
22
23
 
23
- /** The conventional boolean frontmatter field that marks an entry a draft (§7.6). */
24
+ /** The conventional frontmatter boolean that marks an entry a draft (site-architecture.md §7.6). */
24
25
  export const DRAFT_FIELD = "draft";
25
26
 
26
27
  /**
27
28
  * What a draft IS, in one sentence, for every surface that shows the pill.
28
29
  *
29
- * Deliberately does not say "excluded from production builds" — the spec's §7.6 bullet describes an
30
- * intent the build does not implement yet (`packages/compiler`'s `site/site-build.ts` says so
31
- * beside `$sitemap`), and a badge that promises a file will not ship when it will is the exact
32
- * class of confident-wrong statement §16 exists to end. When the compiler learns to drop drafts,
33
- * this constant changes and every surface changes with it.
30
+ * Deliberately does not say "excluded from production builds" — site-architecture.md §7.6's bullet
31
+ * describes an intent the build does not implement yet (`packages/compiler`'s `site/site-build.ts`
32
+ * says so beside `$sitemap`), and a badge that promises a file will not ship when it will is the
33
+ * exact class of confident-wrong statement §16 exists to end. When the compiler learns to drop
34
+ * drafts, this constant changes and every surface changes with it.
34
35
  */
35
36
  export const DRAFT_MEANING =
36
37
  "Marked a draft. Studio filters drafts out of its own lists; the build does not exclude them yet.";
@@ -82,7 +83,7 @@ export function includingDrafts(): boolean {
82
83
  *
83
84
  * A setter, never a toggle: `content.setIncludeDrafts` names the STATE it reaches, so a manifest
84
85
  * step, an assistant call and a checkbox all land on the same value however many times they run
85
- * (plan §13.1, and the rule `tests/app-commands.test.ts` enforces).
86
+ * (§13.5's idempotence rule, which `tests/app-commands.test.ts` enforces).
86
87
  *
87
88
  * Setting the flag is all this does. Repainting the lists that read it belongs to the command — see
88
89
  * `content/entry-commands.ts` — because a data module may not reach into the workspace.