@happyvertical/smrt-svelte 0.55.6 → 0.55.8

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 (318) hide show
  1. package/AGENTS.md +9 -31
  2. package/README.md +195 -5
  3. package/agents/browser-ai.md +47 -0
  4. package/agents/command-palette.md +85 -0
  5. package/agents/import-export.md +62 -0
  6. package/agents/overview-surfaces.md +255 -0
  7. package/agents/screens.md +57 -0
  8. package/agents/workspace.md +202 -5
  9. package/dist/browser-ai/adapters/stt/dictation-source.d.ts.map +1 -1
  10. package/dist/browser-ai/adapters/stt/dictation-source.js +8 -2
  11. package/dist/browser-ai/adapters/stt/factory.d.ts +6 -3
  12. package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -1
  13. package/dist/browser-ai/adapters/stt/factory.js +19 -9
  14. package/dist/browser-ai/adapters/stt/index.d.ts +3 -1
  15. package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -1
  16. package/dist/browser-ai/adapters/stt/index.js +3 -1
  17. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts +111 -0
  18. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts.map +1 -0
  19. package/dist/browser-ai/adapters/stt/local-speech-model.js +377 -0
  20. package/dist/browser-ai/adapters/stt/local-speech.d.ts +82 -0
  21. package/dist/browser-ai/adapters/stt/local-speech.d.ts.map +1 -0
  22. package/dist/browser-ai/adapters/stt/local-speech.js +317 -0
  23. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts +2 -0
  24. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts.map +1 -0
  25. package/dist/browser-ai/adapters/stt/local-speech.worker.js +32 -0
  26. package/dist/browser-ai/adapters/stt/transformers-env.d.ts +8 -0
  27. package/dist/browser-ai/adapters/stt/transformers-env.d.ts.map +1 -0
  28. package/dist/browser-ai/adapters/stt/transformers-env.js +17 -0
  29. package/dist/browser-ai/adapters/stt/types.d.ts +54 -9
  30. package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -1
  31. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +5 -0
  32. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -1
  33. package/dist/browser-ai/adapters/tts/browser-synthesis.js +83 -55
  34. package/dist/browser-ai/capabilities/speech-probe.d.ts +29 -0
  35. package/dist/browser-ai/capabilities/speech-probe.d.ts.map +1 -0
  36. package/dist/browser-ai/capabilities/speech-probe.js +19 -0
  37. package/dist/browser-ai/core/errors.d.ts +9 -0
  38. package/dist/browser-ai/core/errors.d.ts.map +1 -1
  39. package/dist/browser-ai/core/errors.js +12 -0
  40. package/dist/browser-ai/index.d.ts +1 -0
  41. package/dist/browser-ai/index.d.ts.map +1 -1
  42. package/dist/browser-ai/index.js +1 -0
  43. package/dist/components/app/AppShell.svelte +587 -33
  44. package/dist/components/app/AppShell.svelte.d.ts +75 -4
  45. package/dist/components/app/AppShell.svelte.d.ts.map +1 -1
  46. package/dist/components/app/DockToggles.svelte +0 -1
  47. package/dist/components/app/dock-toggle.d.ts +7 -1
  48. package/dist/components/app/dock-toggle.d.ts.map +1 -1
  49. package/dist/components/app/index.d.ts +2 -1
  50. package/dist/components/app/index.d.ts.map +1 -1
  51. package/dist/components/app/slot-item.d.ts +21 -0
  52. package/dist/components/app/slot-item.d.ts.map +1 -0
  53. package/dist/components/app/slot-item.js +1 -0
  54. package/dist/components/command-palette/CommandPalette.svelte +75 -0
  55. package/dist/components/command-palette/CommandPalette.svelte.d.ts +22 -0
  56. package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -0
  57. package/dist/components/command-palette/CommandPaletteDialog.svelte +406 -0
  58. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts +18 -0
  59. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts.map +1 -0
  60. package/dist/components/command-palette/CommandPaletteTrigger.svelte +91 -0
  61. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts +17 -0
  62. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts.map +1 -0
  63. package/dist/components/command-palette/context.d.ts +18 -0
  64. package/dist/components/command-palette/context.d.ts.map +1 -0
  65. package/dist/components/command-palette/context.js +38 -0
  66. package/dist/components/command-palette/controller.svelte.d.ts +70 -0
  67. package/dist/components/command-palette/controller.svelte.d.ts.map +1 -0
  68. package/dist/components/command-palette/controller.svelte.js +379 -0
  69. package/dist/components/command-palette/hotkeys.d.ts +30 -0
  70. package/dist/components/command-palette/hotkeys.d.ts.map +1 -0
  71. package/dist/components/command-palette/hotkeys.js +161 -0
  72. package/dist/components/command-palette/index.d.ts +19 -0
  73. package/dist/components/command-palette/index.d.ts.map +1 -0
  74. package/dist/components/command-palette/index.js +17 -0
  75. package/dist/components/command-palette/match.d.ts +38 -0
  76. package/dist/components/command-palette/match.d.ts.map +1 -0
  77. package/dist/components/command-palette/match.js +172 -0
  78. package/dist/components/command-palette/providers.d.ts +159 -0
  79. package/dist/components/command-palette/providers.d.ts.map +1 -0
  80. package/dist/components/command-palette/providers.js +345 -0
  81. package/dist/components/command-palette/rank.d.ts +20 -0
  82. package/dist/components/command-palette/rank.d.ts.map +1 -0
  83. package/dist/components/command-palette/rank.js +74 -0
  84. package/dist/components/command-palette/types.d.ts +119 -0
  85. package/dist/components/command-palette/types.d.ts.map +1 -0
  86. package/dist/components/command-palette/types.js +10 -0
  87. package/dist/components/command-palette/use-provider.svelte.d.ts +14 -0
  88. package/dist/components/command-palette/use-provider.svelte.d.ts.map +1 -0
  89. package/dist/components/command-palette/use-provider.svelte.js +23 -0
  90. package/dist/components/forms/AddressInput.svelte +2 -15
  91. package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
  92. package/dist/components/forms/DateRangeInput.svelte +2 -15
  93. package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
  94. package/dist/components/forms/DateTimeInput.svelte +8 -15
  95. package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
  96. package/dist/components/forms/MeasurementInput.svelte +2 -15
  97. package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
  98. package/dist/components/forms/MoneyInput.svelte +8 -25
  99. package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
  100. package/dist/components/forms/NumberInput.svelte +7 -15
  101. package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
  102. package/dist/components/forms/PhoneInput.svelte +7 -15
  103. package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
  104. package/dist/components/forms/SelectInput.svelte +34 -40
  105. package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
  106. package/dist/components/forms/TextInput.svelte +20 -37
  107. package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
  108. package/dist/components/forms/TextareaInput.svelte +19 -35
  109. package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
  110. package/dist/components/import-export/ImportExport.svelte +678 -0
  111. package/dist/components/import-export/ImportExport.svelte.d.ts +5 -0
  112. package/dist/components/import-export/ImportExport.svelte.d.ts.map +1 -0
  113. package/dist/components/import-export/collection-adapter.d.ts +35 -0
  114. package/dist/components/import-export/collection-adapter.d.ts.map +1 -0
  115. package/dist/components/import-export/collection-adapter.js +42 -0
  116. package/dist/components/import-export/csv.d.ts +60 -0
  117. package/dist/components/import-export/csv.d.ts.map +1 -0
  118. package/dist/components/import-export/csv.js +192 -0
  119. package/dist/components/import-export/download.d.ts +4 -0
  120. package/dist/components/import-export/download.d.ts.map +1 -0
  121. package/dist/components/import-export/download.js +17 -0
  122. package/dist/components/import-export/export.d.ts +25 -0
  123. package/dist/components/import-export/export.d.ts.map +1 -0
  124. package/dist/components/import-export/export.js +68 -0
  125. package/dist/components/import-export/fields.d.ts +48 -0
  126. package/dist/components/import-export/fields.d.ts.map +1 -0
  127. package/dist/components/import-export/fields.js +103 -0
  128. package/dist/components/import-export/index.d.ts +12 -0
  129. package/dist/components/import-export/index.d.ts.map +1 -0
  130. package/dist/components/import-export/index.js +9 -0
  131. package/dist/components/import-export/mapping.d.ts +12 -0
  132. package/dist/components/import-export/mapping.d.ts.map +1 -0
  133. package/dist/components/import-export/mapping.js +38 -0
  134. package/dist/components/import-export/props.d.ts +34 -0
  135. package/dist/components/import-export/props.d.ts.map +1 -0
  136. package/dist/components/import-export/props.js +1 -0
  137. package/dist/components/import-export/report.d.ts +13 -0
  138. package/dist/components/import-export/report.d.ts.map +1 -0
  139. package/dist/components/import-export/report.js +50 -0
  140. package/dist/components/import-export/runner.d.ts +17 -0
  141. package/dist/components/import-export/runner.d.ts.map +1 -0
  142. package/dist/components/import-export/runner.js +39 -0
  143. package/dist/components/import-export/types.d.ts +100 -0
  144. package/dist/components/import-export/types.d.ts.map +1 -0
  145. package/dist/components/import-export/types.js +6 -0
  146. package/dist/components/import-export/validate.d.ts +39 -0
  147. package/dist/components/import-export/validate.d.ts.map +1 -0
  148. package/dist/components/import-export/validate.js +268 -0
  149. package/dist/components/overview/OverviewGrid.svelte +579 -0
  150. package/dist/components/overview/OverviewGrid.svelte.d.ts +5 -0
  151. package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -0
  152. package/dist/components/overview/WidgetOptionsForm.svelte +193 -0
  153. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts +5 -0
  154. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -0
  155. package/dist/components/overview/controller.svelte.d.ts +92 -0
  156. package/dist/components/overview/controller.svelte.d.ts.map +1 -0
  157. package/dist/components/overview/controller.svelte.js +336 -0
  158. package/dist/components/overview/format.d.ts +13 -0
  159. package/dist/components/overview/format.d.ts.map +1 -0
  160. package/dist/components/overview/format.js +45 -0
  161. package/dist/components/overview/grid-types.d.ts +52 -0
  162. package/dist/components/overview/grid-types.d.ts.map +1 -0
  163. package/dist/components/overview/grid-types.js +1 -0
  164. package/dist/components/overview/index.d.ts +24 -0
  165. package/dist/components/overview/index.d.ts.map +1 -0
  166. package/dist/components/overview/index.js +22 -0
  167. package/dist/components/overview/load.d.ts +30 -0
  168. package/dist/components/overview/load.d.ts.map +1 -0
  169. package/dist/components/overview/load.js +92 -0
  170. package/dist/components/overview/markdown.d.ts +53 -0
  171. package/dist/components/overview/markdown.d.ts.map +1 -0
  172. package/dist/components/overview/markdown.js +203 -0
  173. package/dist/components/overview/model.d.ts +100 -0
  174. package/dist/components/overview/model.d.ts.map +1 -0
  175. package/dist/components/overview/model.js +460 -0
  176. package/dist/components/overview/recipe-widgets.d.ts +77 -0
  177. package/dist/components/overview/recipe-widgets.d.ts.map +1 -0
  178. package/dist/components/overview/recipe-widgets.js +151 -0
  179. package/dist/components/overview/registry.d.ts +45 -0
  180. package/dist/components/overview/registry.d.ts.map +1 -0
  181. package/dist/components/overview/registry.js +112 -0
  182. package/dist/components/overview/resize.d.ts +25 -0
  183. package/dist/components/overview/resize.d.ts.map +1 -0
  184. package/dist/components/overview/resize.js +41 -0
  185. package/dist/components/overview/schema.d.ts +34 -0
  186. package/dist/components/overview/schema.d.ts.map +1 -0
  187. package/dist/components/overview/schema.js +180 -0
  188. package/dist/components/overview/server.d.ts +14 -0
  189. package/dist/components/overview/server.d.ts.map +1 -0
  190. package/dist/components/overview/server.js +13 -0
  191. package/dist/components/overview/types.d.ts +235 -0
  192. package/dist/components/overview/types.d.ts.map +1 -0
  193. package/dist/components/overview/types.js +17 -0
  194. package/dist/components/overview/widgets/ChartWidget.svelte +111 -0
  195. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +6 -0
  196. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -0
  197. package/dist/components/overview/widgets/MetricWidget.svelte +86 -0
  198. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts +6 -0
  199. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts.map +1 -0
  200. package/dist/components/overview/widgets/NoteWidget.svelte +61 -0
  201. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts +5 -0
  202. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts.map +1 -0
  203. package/dist/components/overview/widgets/RecordListWidget.svelte +91 -0
  204. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts +6 -0
  205. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -0
  206. package/dist/components/overview/widgets/ShortcutsWidget.svelte +80 -0
  207. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts +6 -0
  208. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -0
  209. package/dist/components/overview/widgets/core.d.ts +44 -0
  210. package/dist/components/overview/widgets/core.d.ts.map +1 -0
  211. package/dist/components/overview/widgets/core.js +222 -0
  212. package/dist/components/overview/widgets/data.d.ts +76 -0
  213. package/dist/components/overview/widgets/data.d.ts.map +1 -0
  214. package/dist/components/overview/widgets/data.js +40 -0
  215. package/dist/components/screens/DetailScreen.svelte +220 -0
  216. package/dist/components/screens/DetailScreen.svelte.d.ts +5 -0
  217. package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -0
  218. package/dist/components/screens/EditForm.svelte +313 -0
  219. package/dist/components/screens/EditForm.svelte.d.ts +5 -0
  220. package/dist/components/screens/EditForm.svelte.d.ts.map +1 -0
  221. package/dist/components/screens/ListScreen.svelte +191 -0
  222. package/dist/components/screens/ListScreen.svelte.d.ts +5 -0
  223. package/dist/components/screens/ListScreen.svelte.d.ts.map +1 -0
  224. package/dist/components/screens/RecipeScreens.svelte +237 -0
  225. package/dist/components/screens/RecipeScreens.svelte.d.ts +5 -0
  226. package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -0
  227. package/dist/components/screens/fields.d.ts +54 -0
  228. package/dist/components/screens/fields.d.ts.map +1 -0
  229. package/dist/components/screens/fields.js +229 -0
  230. package/dist/components/screens/index.d.ts +8 -0
  231. package/dist/components/screens/index.d.ts.map +1 -0
  232. package/dist/components/screens/index.js +6 -0
  233. package/dist/components/screens/types.d.ts +215 -0
  234. package/dist/components/screens/types.d.ts.map +1 -0
  235. package/dist/components/screens/types.js +1 -0
  236. package/dist/components/screens/values.d.ts +62 -0
  237. package/dist/components/screens/values.d.ts.map +1 -0
  238. package/dist/components/screens/values.js +289 -0
  239. package/dist/components/sortable/Sortable.svelte +6 -33
  240. package/dist/components/sortable/Sortable.svelte.d.ts.map +1 -1
  241. package/dist/components/sortable/announce.d.ts +5 -0
  242. package/dist/components/sortable/announce.d.ts.map +1 -0
  243. package/dist/components/sortable/announce.js +33 -0
  244. package/dist/components/sortable/controller.svelte.d.ts +10 -0
  245. package/dist/components/sortable/controller.svelte.d.ts.map +1 -1
  246. package/dist/components/sortable/controller.svelte.js +29 -7
  247. package/dist/components/workspace/admin-shell/AdminShell.svelte +424 -58
  248. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +27 -2
  249. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
  250. package/dist/components/workspace/admin-shell/ShellBrand.svelte +86 -0
  251. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts +18 -0
  252. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts.map +1 -0
  253. package/dist/components/workspace/admin-shell/ShellIconButton.svelte +77 -0
  254. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts +26 -0
  255. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts.map +1 -0
  256. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte +88 -16
  257. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte.d.ts.map +1 -1
  258. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte +531 -0
  259. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts +26 -0
  260. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts.map +1 -0
  261. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte +57 -0
  262. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts +22 -0
  263. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts.map +1 -0
  264. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte +290 -0
  265. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts +32 -0
  266. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts.map +1 -0
  267. package/dist/components/workspace/admin-shell/TenantNav.svelte +67 -2
  268. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +8 -0
  269. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
  270. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts +67 -0
  271. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts.map +1 -1
  272. package/dist/components/workspace/admin-shell/layout-controller.svelte.js +129 -1
  273. package/dist/components/workspace/admin-shell/layout.d.ts +122 -0
  274. package/dist/components/workspace/admin-shell/layout.d.ts.map +1 -1
  275. package/dist/components/workspace/admin-shell/layout.js +410 -10
  276. package/dist/components/workspace/admin-shell/settings.js +4 -4
  277. package/dist/components/workspace/admin-shell/shell-icons.d.ts +45 -0
  278. package/dist/components/workspace/admin-shell/shell-icons.d.ts.map +1 -0
  279. package/dist/components/workspace/admin-shell/shell-icons.js +66 -0
  280. package/dist/components/workspace/admin-shell/slot-labels.d.ts +33 -0
  281. package/dist/components/workspace/admin-shell/slot-labels.d.ts.map +1 -0
  282. package/dist/components/workspace/admin-shell/slot-labels.js +33 -0
  283. package/dist/components/workspace/admin-shell/slots.d.ts +50 -0
  284. package/dist/components/workspace/admin-shell/slots.d.ts.map +1 -0
  285. package/dist/components/workspace/admin-shell/slots.js +77 -0
  286. package/dist/components/workspace/admin-shell/state.svelte.d.ts +35 -0
  287. package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
  288. package/dist/components/workspace/admin-shell/state.svelte.js +111 -0
  289. package/dist/components/workspace/admin-shell/types.d.ts +101 -1
  290. package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
  291. package/dist/components/workspace/index.d.ts +9 -2
  292. package/dist/components/workspace/index.d.ts.map +1 -1
  293. package/dist/components/workspace/index.js +6 -0
  294. package/dist/components/workspace/manifest-nav.d.ts +20 -0
  295. package/dist/components/workspace/manifest-nav.d.ts.map +1 -1
  296. package/dist/components/workspace/manifest-nav.js +42 -13
  297. package/dist/i18n/server.d.ts +6 -0
  298. package/dist/i18n/server.d.ts.map +1 -1
  299. package/dist/i18n/server.js +6 -0
  300. package/dist/i18n/strings.import-export.d.ts +88 -0
  301. package/dist/i18n/strings.import-export.d.ts.map +1 -0
  302. package/dist/i18n/strings.import-export.js +88 -0
  303. package/dist/i18n/strings.overview.d.ts +100 -0
  304. package/dist/i18n/strings.overview.d.ts.map +1 -0
  305. package/dist/i18n/strings.overview.js +107 -0
  306. package/dist/i18n/strings.palette.d.ts +18 -0
  307. package/dist/i18n/strings.palette.d.ts.map +1 -0
  308. package/dist/i18n/strings.palette.js +18 -0
  309. package/dist/i18n/strings.screens.d.ts +31 -0
  310. package/dist/i18n/strings.screens.d.ts.map +1 -0
  311. package/dist/i18n/strings.screens.js +31 -0
  312. package/dist/i18n/strings.workspace.d.ts +49 -0
  313. package/dist/i18n/strings.workspace.d.ts.map +1 -1
  314. package/dist/i18n/strings.workspace.js +49 -0
  315. package/package.json +59 -19
  316. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +0 -51
  317. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +0 -1
  318. package/dist/browser-ai/adapters/stt/whisper-wasm.js +0 -380
@@ -0,0 +1,255 @@
1
+ # smrt-svelte/overview
2
+
3
+ Module semantics for `src/components/overview/` (`./overview` and
4
+ `./overview/server`, #3727). Package orientation and cross-module invariants are
5
+ in [../AGENTS.md](../AGENTS.md); the shell edit mode it joins is in
6
+ [workspace.md](workspace.md#editing-the-layout-in-place).
7
+
8
+ An overview is a **customizable surface**: a flow grid of registered widgets,
9
+ each with an options object. A page declares which widget types it allows and
10
+ its default arrangement; admins (or users, per role) add, reorder, resize,
11
+ configure and remove widgets inside that confined set, and reset returns to the
12
+ default. Phase 1 (this module) is the surface, the registry, the data model, the
13
+ server load contract and five core widgets; phase 2 adds package widgets from
14
+ recipes ("Recipe widgets"). Persistence and assistant operations are later
15
+ phases (see "Extension points").
16
+
17
+ ## Two entries
18
+
19
+ | Entry | Contents |
20
+ |---|---|
21
+ | `./overview/server` (`server.ts`) | Svelte-free: types, `validateWidgetOptions`, the model (`resolveOverview`, `checkOverviewOverride`, `applyOverviewOverride`, `diffOverview`, `sanitizeOverview`, ...), `WidgetRegistry` / `registerWidget`, `loadOverview`. Safe in a `+page.server.ts` or a save endpoint. |
22
+ | `./overview` (`index.ts`) | Everything above plus `OverviewGrid`, `createOverview` (controller), `WidgetOptionsForm`, the core widgets and `registerCoreWidgets`, `shortcutsFromNav`, `formatWidgetValue`, `parseMarkdown` / `safeHref`. |
23
+
24
+ ## Data model (`types.ts`, `model.ts`)
25
+
26
+ A saved overview is data, never code:
27
+ `{ widgets: [{ id, type, span, options, version? }] }`. `span` is 1 to 4 (a widget
28
+ type may narrow its own range); `options` is a flat object of JSON primitives;
29
+ `version` is the widget's option-schema version the options were written
30
+ against (absent means 1).
31
+
32
+ - **`OverviewDefinition`** (what a page declares): `id` (dotted ids allowed,
33
+ `events.home`), `defaults`, `allowed` (widget types; omit for every registered
34
+ type), `models` (confines `model` options, including a substituted default: a
35
+ default outside the list fails validation, so its loader never runs),
36
+ `maxWidgets` (default 24).
37
+ `defineOverview` validates ids.
38
+ - **`OverviewOverride`** is the sparse, versioned (`version: 1`) delta a host
39
+ stores: `order`, `removed`, `added`, `changed[id] = { span?, options?, version? }`.
40
+ `applyOverviewOverride(base, override)` is total: ids the base no longer has
41
+ are ignored, an added widget colliding with a base id is skipped, and widgets
42
+ the order does not list keep their slots (a default shipped later still
43
+ appears). `diffOverview(base, next)` is its inverse (round-trip tested), so
44
+ every client edit is "mutate the document, store the diff"; an edit that
45
+ returns to the defaults stores `null`.
46
+ - **Ids are stable.** `nextWidgetId` yields `w<n>` and reserves the ids of
47
+ removed defaults, so a new widget never takes a removed default's id (the
48
+ override would delete it). It is total for any stored ids: numeric suffixes
49
+ beyond `Number.MAX_SAFE_INTEGER` are ignored when picking the next number
50
+ (they would stop incrementing), and an exhausted high end restarts at `w1`.
51
+ - **Tiers.** `resolveOverview` merges one override. A host with tenant defaults
52
+ and user overrides merges the tenant tier into the definition's `defaults`
53
+ first (phase 3); the user override then applies to that.
54
+ - **Reset** is `controller.reset()` (store `null`) or `resetWidget(id)`.
55
+
56
+ ## Validation: what keeps a stored overview from running anything
57
+
58
+ Options are validated against the widget's versioned schema on **save**
59
+ (`checkOverviewOverride`, strict: any issue rejects, and the returned override is
60
+ re-derived from the sanitized result, so persist that) and on **load**
61
+ (`sanitizeOverview`, lenient: the bad widget is dropped and reported as an
62
+ `OverviewIssue`, the rest render). Nothing here calls a widget's `load` for a
63
+ widget that failed validation.
64
+
65
+ - `schema.ts` field types: `text`, `markdown`, `identifier`, `model`, `integer`,
66
+ `number`, `boolean`, `enum`. There is **no free-form query, filter expression,
67
+ URL or SQL field**. "Which data" is a `model` (a bare `Class`, `pkg:Class` or
68
+ `@scope/pkg:Class`, optionally confined to the page's `models`), an
69
+ `identifier` (a field or named-filter id, `[A-Za-z_][A-Za-z0-9_.-]{0,63}`) or a
70
+ closed `enum`. The loader maps those to queries it owns and authorizes.
71
+ - Strict: unknown keys, wrong types, out-of-range numbers, values outside a closed
72
+ set and missing required fields fail the whole options object. Missing optional
73
+ fields take their default; `null` counts as missing.
74
+ - `sanitizeOverview` also drops: unknown types, types outside the page's
75
+ `allowed` set or a widget's `allowedIn`, duplicate ids, widgets over the cap,
76
+ newer-than-known versions, and older versions without a working `migrate`.
77
+ Spans are clamped to the widget's range. It is idempotent.
78
+ - `migrate(options, fromVersion)` upgrades stored options to the current version
79
+ (return `null` to drop). It runs on untrusted input inside a try/catch, and its
80
+ result is validated like any other options.
81
+ - A widget id removed by the user and a type removed by a release both degrade to
82
+ "dropped and reported", never an error page.
83
+
84
+ ## Registry (`registry.ts`)
85
+
86
+ `registerWidget({ type, title, options, component | loadComponent, load, allowedIn,
87
+ version, migrate, defaultSpan, minSpan, maxSpan })` on the shared
88
+ `defaultWidgetRegistry`, or `createWidgetRegistry()` for an isolated one (tests,
89
+ several surfaces). Registration is code, at module scope; registering a type
90
+ twice throws unless `{ replace: true }`. `title`, `description` and option
91
+ `label` / `help` / `choices[].label` are text **or i18n keys** (the UI runs them
92
+ through `t`, which returns an unregistered string unchanged); the core widgets
93
+ use `ui.overview.*` keys from `i18n/strings.overview.ts` (registered in
94
+ `i18n/server.ts`).
95
+
96
+ `component` renders synchronously. `loadComponent` is the lazy form (dynamic import
97
+ by export ref): resolve it **before** render with `resolveWidgetComponents(types)`
98
+ in a universal load and pass the map to `OverviewGrid components`, so server and
99
+ client render the same tree. A type that cannot resolve renders as unavailable.
100
+
101
+ ## Server load contract (`load.ts`)
102
+
103
+ ```ts
104
+ // +page.server.ts
105
+ const resolved = resolveOverview(definition, await storedOverride(event), registry);
106
+ const overview = await loadOverview(resolved.document, definition, registry, {
107
+ locale, tenantId, db /* the request's permission-checked capabilities */,
108
+ });
109
+ return { overview }; // LoadedOverview: JSON, serializable
110
+ ```
111
+
112
+ - A widget's `load(options, ctx)` receives **validated options only** and a
113
+ `WidgetLoadContext` the host built from the request principal: `overviewId`, an
114
+ abort `signal`, `locale`, and any host capabilities (index keys). It must
115
+ authorize through `ctx` (the user's permissions and tenant filters), never
116
+ through option values. Reports-backed chart loaders call the runtime-report
117
+ compiler with this context; this package does not depend on it.
118
+ - Loads run in parallel with a per-widget timeout (default 8 s; the signal
119
+ aborts). A thrown error, a timeout or non-serializable / oversized data
120
+ (default 256 KB of JSON) becomes a per-widget error tile
121
+ (`error.code`: `load_failed | timeout | invalid_data`); the real error goes only
122
+ to `onError` for server logs, never to the client. One bad widget never fails
123
+ the page.
124
+ - `LoadedOverview` is what the page returns and `createOverview({ loaded })` seeds
125
+ the controller from, so the grid renders every widget at first paint with no
126
+ client-only fetching and **no hydration mismatch** (the grid has no
127
+ effect-dependent content; the only `$effect` requests data for widgets the
128
+ seeded entries do not cover, which never happens on first render).
129
+ `scripts/overview-ssr.test.mjs` renders the grid through Vite SSR.
130
+ - Formatting is deterministic per locale (`Intl` with the i18n store's locale), and
131
+ no widget formats dates or reads the clock; loaders send preformatted meta.
132
+
133
+ ## Controller (`controller.svelte.ts`)
134
+
135
+ `createOverview({ definition, registry?, override?, onchange?, canCustomize?,
136
+ loaded?, loadWidget? })`, the `ShellLayout` pattern: **persistence is host-owned**.
137
+ With an `override` getter the host is the source of truth and feeds each edit back
138
+ (`onchange(override | null)`); without it the value is kept in memory. Reactive
139
+ reads: `document`, `base`, `override`, `issues`, `customized`, `canCustomize`,
140
+ `addable`, `full`, `entry(widget)`. Operations, each returning
141
+ `{ ok: true, id } | { ok: false, reason, issues? }` and refused with
142
+ `not_allowed` when `canCustomize()` is false (the role gate; the server must check
143
+ the same on save): `add(type, options?)`, `remove`, `move(id, toIndex)` (index
144
+ after removal), `resize(id, span)`, `setOptions`, `resetWidget`, `reset`,
145
+ `restore(override)` (the Undo hook), `reload(id)`.
146
+
147
+ `loadWidget(widget, signal)` is how a client edit gets data for an added or
148
+ reconfigured widget: the host runs the widget's `load` where its data lives (a
149
+ remote function in production, the in-browser source in smrt-planner). The
150
+ controller drops results for stale option keys and aborts superseded loads.
151
+ Call `destroy()` when the owner unmounts.
152
+
153
+ ## Grid and edit mode (`OverviewGrid.svelte`)
154
+
155
+ Props in `grid-types.ts`. `editing` defaults to the shell's layout editor
156
+ (`tryUseShellLayout()?.editing`), so the same pencil edits the grid under an
157
+ `AppShell` with `layoutEditing`; pass `editing` to drive it without a shell. It is
158
+ off whenever `controller.canCustomize` is false.
159
+
160
+ - **Flow grid.** CSS grid of 4 columns, 2 below 40rem and 1 below 22rem of the
161
+ grid's own width (container queries); `data-span` / `--span` carry the span. Gaps
162
+ are tile padding, not grid gap, so a drag never crosses a dead zone.
163
+ - **Reorder** uses the headless `createSortable` engine in its `flow` mode (a
164
+ single wrapping list): the handle is the existing grip (Space picks up, any
165
+ arrow steps along reading order, mirrored in RTL, Enter drops, Escape cancels;
166
+ pointer and native drag use the horizontal midpoint for tiles sharing a row).
167
+ - **Resize** is an end-edge `role="slider"` (arrows, Home, End; pointer drag snaps
168
+ to a column boundary via the pure `spanFromPointer`, committed on release).
169
+ - **Chrome** is icon-only `ShellIconButton`s (configure, remove) plus the toolbar
170
+ (add, reset). Widgets render as on the site inside an `inert` wrapper. Add and
171
+ configure open `Modal`s; `WidgetOptionsForm` is generated from the option field
172
+ descriptors with smrt-ui `Form` / `FormGroup` / `Input` / `Select` / `Textarea` /
173
+ `Checkbox` (the descriptors mirror the generated screens' field shape) and shows
174
+ each schema issue beside its field. A widget with a required option and no
175
+ default opens the form before it is added.
176
+ - A polite live region announces moves, resizes, adds, removals and resets.
177
+ `OverviewGrid.test.ts` runs axe in view and edit mode.
178
+
179
+ ## Core widgets (`widgets/`)
180
+
181
+ `registerCoreWidgets(registry, loaders)` registers `note` always and each
182
+ data-backed widget only when its loader is given (structural injection: this
183
+ package depends on no data package). Widgets render only when the grid has
184
+ `ready` data (it draws loading and error tiles) and treat `data` as untrusted
185
+ shape. Data shapes are in `widgets/data.ts`.
186
+
187
+ | Type | Options | Data |
188
+ |---|---|---|
189
+ | `metric` | `title`, `model`*, `measure`, `field`, `filter` | `{ value, format?, currency?, label?, change?, href? }` (money = integer minor units) |
190
+ | `chart` | `title`, `model`*, `groupBy`, `measure`, `field`, `period`, `style` (bar/line), `filter` | `{ points: [{ label, value }], format?, currency?, href? }`, one measure of a runtime report |
191
+ | `records` | `title`, `model`*, `sort`, `direction`, `limit`, `filter` | `{ rows: [{ id, title, subtitle?, meta?, href? }], total?, href? }`; the loader chooses the title field and the visible records |
192
+ | `shortcuts` | `title`, `section` | `{ items: [{ id, label, href, icon?, description? }] }`; `shortcutsFromNav(sections, sectionId)` maps `resolveShellNavModel` / `useShellLayout().sections` (visible entries, user renames) |
193
+ | `note` | `title`, `body` (Markdown) | none |
194
+
195
+ `note` renders `parseMarkdown` output as elements (headings, paragraphs, lists,
196
+ quotes, fenced code, bold/italic/code/links). There is no `{@html}`; raw HTML is
197
+ literal text and `safeHref` limits links to http(s), mailto, same-site paths and
198
+ fragments. Record and shortcut hrefs pass `safeHref` too. Charts carry their
199
+ numbers as text (inline for bars, a visually hidden table for the line).
200
+
201
+ ## Recipe widgets (`recipe-widgets.ts`)
202
+
203
+ A package contributes a widget with a `widget` surface on a recipe
204
+ ([core recipes.md](../../core/agents/recipes.md#widget-surfaces-3727) has the
205
+ declaration and its scan-time rules). `registerRecipeWidgets(registry, recipes,
206
+ resolveExport, { replace?, enabled? })` (async, Svelte-free, on both entries)
207
+ turns the manifest's widget surfaces into `registry.register(...)` calls:
208
+
209
+ | Surface field | Registration |
210
+ |---|---|
211
+ | `type`, `label`, `description`, `icon`, `version` | `type`, `title`, `description`, `icon`, `version` |
212
+ | `options` | `options` (plain JSON; `registry.register` re-validates the schema) |
213
+ | `export` | `loadComponent` (lazy; the export may be a component or a `{ default }` module) |
214
+ | `data.load` | `load` (resolved on first use; a missing or non-function loader is that widget's error tile) |
215
+ | `migrate` | `migrate`, **resolved eagerly** because the registry's `migrate` is synchronous |
216
+ | `allowedIn`, `defaultSpan`, `minSpan`, `maxSpan` | same names |
217
+ | `data.models` | not registered: documentation of what the loader reads; confine with the page's `models` |
218
+
219
+ - **The module resolver is injected.** `resolveExport(specifier, exportName)` is
220
+ the host's: a static map of dynamic imports in a bundled app, a stub in tests.
221
+ Nothing is imported when the manifest is read, and the registration itself
222
+ imports nothing except `migrate` exports. Relative or absolute specifiers
223
+ are refused.
224
+ - **Never throws for a bad surface.** The result is `{ registered, skipped,
225
+ dispose }`; a skip carries `reason` `duplicate_type` (a core widget or another
226
+ recipe owns the type; `replace` overrides), `invalid` (the registry refused the
227
+ definition) or `unresolved` (a `migrate` export is missing). One broken package
228
+ cannot take down the overview.
229
+ - **`enabled(recipeId)`** keeps widgets of recipes that are off out of the add
230
+ list. Call the helper again (after `dispose()`) when the set changes.
231
+ - Widget types share one registry namespace with the core widgets
232
+ (`metric`, `chart`, `records`, `shortcuts`, `note`). Pages still confine what
233
+ can appear with `defineOverview({ allowed })`, and a widget with `allowedIn`
234
+ only validates inside those overview ids.
235
+ - `src/components/overview/__tests__/recipe-widgets.test.ts` covers lazy
236
+ resolution, the loader and migrate paths, allowed placements and the skip
237
+ reasons. The scanner's copy of the option vocabulary and patterns is checked
238
+ against `types.ts` / `schema.ts` by `packages/scanner/src/__tests__/recipe-widgets.test.ts`,
239
+ and a type-level assertion here keeps `RecipeWidgetOptionType` equal to
240
+ `WidgetOptionType`.
241
+
242
+ ## Extension points left for later phases
243
+
244
+ - **Phase 2, package widgets (#3727, done).** See "Recipe widgets" below.
245
+ - **Phase 3, production persistence.** Implement the `override` getter /
246
+ `onchange` pair against the `_smrt_` table (tenant tier merged into
247
+ `definition.defaults`, user tier as the override), validate saves with
248
+ `checkOverviewOverride` and persist its canonical `override`, run
249
+ `loadOverview` in the page load, and supply `loadWidget` as a remote function
250
+ that calls the same `load`. Role gating = `canCustomize` plus the same check in
251
+ the save endpoint. No migration or table lives in this package.
252
+ - **Phase 4, assistant.** The controller methods are the structured operations;
253
+ `restore(override)` plus the `override` getter give Undo (snapshot before,
254
+ restore after). `OverviewOpResult.issues` is the validation feedback to return.
255
+ - **Not built:** the activity widget (Track B, #3710) and agenda.
@@ -0,0 +1,57 @@
1
+ # smrt-svelte/screens
2
+
3
+ Module semantics for `src/components/screens/` (`./screens`). Package orientation, the cross-module
4
+ invariants, and the traps that apply before editing anything live in
5
+ [../AGENTS.md](../AGENTS.md) — read that first.
6
+
7
+ ## Manifest-derived record screens (`./screens`, #3718)
8
+
9
+ `RecipeScreens` is the default screen set for a package that ships models but no
10
+ consumer UI (tags, facts, secrets, profiles, reports, prompts). It composes
11
+ `ListScreen`, `DetailScreen` and `EditForm`, each of which can also be used on
12
+ its own. Every screen takes a generated web `definition`
13
+ (`ScreenCollectionDefinition`, structurally a `SmrtWebCollectionDefinition`) and
14
+ an optional resolved `policy` (`ScreenPolicy`, structurally smrt-fields'
15
+ `ResolvedObjectFieldPolicy`). The module imports neither package: smrt-svelte
16
+ stays below the domain layer, and the app passes both in as props.
17
+
18
+ - **Field selection is `fields.ts`, pure and node-testable.** `deriveScreenFields`
19
+ is the single rule for list / view / edit. A field renders only when it is in
20
+ BOTH the definition and the policy, so sensitive, transient and
21
+ read-permission-gated fields (which the policy resolver omits) can never appear
22
+ on a generated screen. Hidden fields are dropped; system fields (`id`,
23
+ `tenantId`, `createdBy`, `updatedBy`, `createdAt`, `updatedAt`) are never
24
+ editable, and the two timestamps appear on a view as read-only advanced meta.
25
+ Do not add a second selection rule in a component.
26
+ - **Without a policy the code seed applies**: `ui.basic` / `ui.group` / `ui.order`
27
+ hints and the cold-start rule (no `basic` markers => everything basic; any
28
+ marker => unmarked fields advanced). Order is `order`, then declaration order.
29
+ - **Tiers**: list shows basic scalar columns only (no long text, JSON or raw
30
+ reference columns; capped at `DEFAULT_MAX_LIST_COLUMNS`, an explicit `columns`
31
+ list is never capped); view and edit show advanced fields behind a disclosure
32
+ (the edit one opens itself when an advanced field has a problem). Policy
33
+ `label`, `help` and `required` win over the manifest; on create, a resolved
34
+ policy default (an explicit `null` included) beats the manifest default.
35
+ `locked` governs who may change the POLICY, never the record value, so it is
36
+ not applied here.
37
+ - **Values are `values.ts`**: money (`ui.widget: 'currency'` on an INTEGER field
38
+ only) is integer minor units end to end. Editing shows major units but converts
39
+ with exact string math (`majorStringToMinorUnits`), never `* 100`; integers are
40
+ rejected unless JavaScript-safe; datetimes go out as ISO strings (an unchanged datetime keeps the
41
+ loaded record's full precision via `parseDraft`'s `record` context; the control
42
+ only shows minutes); JSON as parsed values. Empty optional text becomes `null` when the field is nullable and `''`
43
+ otherwise (unset text persists as `''`); every other empty optional field is
44
+ `null`. Errors are codes, mapped to messages by the component via `useI18n`.
45
+ - **Transport-neutral.** `RecipeScreens` drives a `RecipeScreensSource`
46
+ (`list` / `get` / `create` / `update` / `delete`); an operation the source lacks
47
+ (or `can` turns off) is simply not offered, so a read-only source is a
48
+ read-only screen set. `view` and `recordId` are bindable and `onnavigate`
49
+ fires on every user navigation, so an app can mirror them into its router.
50
+ `EditForm.onsubmit` throws to report a failed save or returns `{ fieldErrors }`.
51
+ Remount `EditForm` with `{#key}` when switching records (`RecipeScreens` does).
52
+ - **Not the policy-editing surface.** The policy gear, field-usage telemetry and
53
+ the per-field renderer registry live in `ObjectForm`
54
+ (`@happyvertical/smrt-fields/svelte`); `EditForm` is the dependency-light
55
+ default and does not replace it. Not wired into recipe surfaces yet (#3708).
56
+ - Component props live in `types.ts`, not in the `.svelte` files, so the barrel
57
+ never re-exports types from a component.
@@ -83,6 +83,140 @@ and touch input across mobile widths and desktop panel-state combinations.
83
83
 
84
84
  See `src/components/workspace/MIGRATION.md` for the old-to-new concept map.
85
85
 
86
+ ### Regions and slots
87
+
88
+ Four regions map to the existing edges (ids and `ShellLayout.panels` keys are
89
+ unchanged): Header (`top`), Left sidebar (`left`), Right sidebar (`right`),
90
+ Footer (`bottom`). Default labels are those names; override via `config`.
91
+ `AdminShell`/`AppShell` take `slots?: Partial<Record<ShellSlot, Snippet>>`
92
+ (`ShellSlot` from `./workspace`): `header.start|center|end`,
93
+ `footer.start|center|end`, `leftSidebar.header|footer`,
94
+ `rightSidebar.header|footer`. Header/footer slots sit in the bar (start after
95
+ the brand/menu opener, end after the account), sidebar header sits above and
96
+ footer below the sidebar's main area. Defaults: brand/title/menu opener/account
97
+ stay where they were (`header.start`/`header.end` areas), `tenantFooter` stays
98
+ the left sidebar footer, `dockToggles` default to `header.end`. There is no
99
+ separate header row.
100
+
101
+ Fallback when a slot's region is hidden (or a sidebar is collapsed), first
102
+ visible wins (`slotFallbackChain`): header.X -> leftSidebar.header ->
103
+ rightSidebar.header -> footer.X; footer.X -> leftSidebar.footer ->
104
+ rightSidebar.footer -> header.X; leftSidebar.header -> header.start ->
105
+ rightSidebar.header -> footer.start; leftSidebar.footer -> footer.start ->
106
+ header.start -> rightSidebar.footer; rightSidebar.header -> header.end ->
107
+ leftSidebar.header -> footer.end; rightSidebar.footer -> footer.end ->
108
+ header.end -> leftSidebar.footer. The legacy `tenantFooter` prop keeps its own
109
+ `footerInHeader` fallback.
110
+
111
+ ### Edge toggles and hotkeys are opt-in (#3661)
112
+
113
+ `AdminShell`/`AppShell` `edgeToggles?: boolean | Partial<Record<PanelEdge,
114
+ boolean>>` defaults to `false`: no edge toggle buttons, no hotkey hints, and
115
+ WASD/`?` are inert. Regions are laid out inline: the left sidebar is docked
116
+ open off phones (`ShellState.setInlineEdges`/`isInline`; viewport defaults and
117
+ `overlayMedia` do not apply), and the header/footer are plain bands without a
118
+ drop-down drawer (so `appPanel`/`systemPanel` are not reachable). Visibility
119
+ comes from `ShellLayout.panels.visible` and edit mode. The right edge is the
120
+ dock: dock toggles and focus tools still open it, it just loses its button.
121
+ `hotkeys` (default: follows the toggles) forces shortcuts on (`true`, panels
122
+ behave as drop-downs without buttons) or off. Phones keep the Menu opener and
123
+ the left drawer's close toggle. `showTenantToggle` is a deprecated alias for
124
+ `edgeToggles.left`. Migration: pass `edgeToggles` (true) to keep the previous
125
+ behaviour.
126
+
127
+ ### Moving items between slots
128
+
129
+ Movable items have stable ids: dock toggles `dock:<tool>`, each host `slots`
130
+ snippet `slot:<slot>`, and host `slotItems` (`AppShell`, `{ id, label, slot,
131
+ render }[]`, exported type `ShellSlotItem`; keep ids stable, they are stored in
132
+ layouts). `AppShell` also supplies the built-in item `item:brand` (the shell
133
+ `logoSrc`/`logoAlt`, title and subtitle, linked to `homeHref` when set, default slot `header.start`, movable, same fallback chain
134
+ when the header is hidden); it sets `AdminShell` `brandInSlot` so the top band
135
+ draws no brand of its own (standalone `AdminShell` still does). The menu
136
+ opener and account content are not items yet (#3656 step 3).
137
+
138
+ `ShellLayout.placements?: Record<itemId, ShellSlot>` (additive, still version
139
+ 1) overrides default slots. Pure helpers in `layout.ts` (also `./workspace/layout`):
140
+ `placeShellItem(layout, id, slot, defaultSlot?)` (passing the default drops a
141
+ no-op override; re-placing puts the item last), `resetShellItemPlacement`,
142
+ `resolveShellPlacements(items, layout)` (default order first, then placement
143
+ order; unknown ids and slots ignored) and `resolveShellVisiblePlacements(items,
144
+ layout, visible)` (placement first, then the hidden-region fallback above).
145
+ `useShellLayout()` adds `placeItem(id, slot)`, `resetItem(id)`, and readers
146
+ `placementItems`, `placements` (per slot) and `isRegionVisible(region)`.
147
+
148
+ ### Editing the layout in place
149
+
150
+ `AppShell` `layoutEditing?: boolean | { slot?; floating? }` opts in (off: no toggle,
151
+ `setEditing(true)` refused, existing apps unchanged). It adds the built-in item
152
+ `item:layout-edit` (default slot `header.end`, normal hidden-region fallback):
153
+ a pencil `ShellIconButton` named "Edit layout" with `aria-pressed`; the same
154
+ button turns edit mode off (it stays a pencil, highlighted while on). Escape
155
+ also exits when no section toolbar is open (an open toolbar, or a keyboard move,
156
+ consumes Escape first).
157
+ `{ floating: true }` instead renders the same button fixed in the top-right
158
+ corner (round, elevated, safe-area aware, z-index 45): not a slot item, not
159
+ movable, never displaced by hidden regions. The header reserves end padding for
160
+ it, or, when the header is hidden, the right sidebar reserves top padding, or main
161
+ does when no right sidebar is shown
162
+ (`--smrt-shell-floating-reserve-inline|block|main`, set by `AppShell`).
163
+ A polite live region announces the mode. `useShellLayout()` has
164
+ `editable`, `editing` and `setEditing(boolean)` for hosts and assistants.
165
+
166
+ While `editing`:
167
+
168
+ - `AdminShell` `layoutEdit` (`ShellLayoutEditSurface`, set by `AppShell`) renders
169
+ every slot of a visible region as a dashed drop zone (entering edit mode
170
+ expands a collapsed left/right sidebar so its header/footer zones exist, and
171
+ leaving restores it; a railless `rail: false` edge is never revealed: it
172
+ stays as the user left it, and while editing a closed railless right edge
173
+ with focus/dock tools shows a slim "Open <tool>" indicator tab
174
+ (`data-edit-indicator`, z 21, no layout shift) that opens it and closes it
175
+ again on exit) (`data-smrt-edit-zone`)
176
+ labelled "Header · Left", empty ones included, highlighted
177
+ (`data-drop-target`) while a drag targets it. Movable items render exactly as
178
+ on the site (inside an `inert` wrapper) with a grip; the toggle itself is
179
+ fixed. One headless `createSortable` engine (confined to the shell root,
180
+ `allowSameContainerReorder: false`) drives pointer, native-drag and keyboard
181
+ moves (Space, Up/Down across zones in visual order, Enter drops, Escape
182
+ cancels) with the same announcements as `Sortable`
183
+ (`sortable/announce.ts`), committing `placeItem(id, slot)`. Items whose region
184
+ is hidden show in the zone they fall back to.
185
+ - Nothing in the header band renders outside the drop zones except each
186
+ region's edit control: the brand is an item in `header.start`, and the Menu
187
+ opener is hidden off phones. Every region, a collapsed sidebar rail included, gets an icon-only eye-off
188
+ "Hide <region>" button (`ShellLayoutEditSurface.regionControl`, end of the
189
+ header/footer band, top of a sidebar) that writes
190
+ `setPanel(edge, { visible: false })`; the strip's "Show" restores it. The
191
+ last visible region's button is disabled with an explanatory tooltip. Items
192
+ of a hidden region (the edit toggle included) follow the fallback chain.
193
+ Hiding the right sidebar (the dock) makes `useShellDock().available` false:
194
+ dock toggles render unregistered and `open` is refused until it is shown.
195
+ - Hidden, available regions render as thin dashed strips ("Right sidebar ·
196
+ hidden") with an eye "Show <region>" button (`setPanel(edge, { visible })`).
197
+ - `ShellNavEditor` replaces `TenantNav`: the real rows plus grips on every
198
+ heading and item (existing reorder/move-across-sections), icon-only
199
+ `ShellIconButton`s (eye `aria-pressed` = shown in navigation, heading
200
+ `aria-pressed` = title shown, host actions) on each section and an eye per
201
+ item, and a "New section" button at the end.
202
+ - Clicking a section heading opens its floating toolbar (rename input focused,
203
+ title, hide, delete for custom sections with a confirm when non-empty, host
204
+ actions). With `(hover: hover) and (pointer: fine)` hovering also opens it
205
+ (closes on leave unless a click pinned it); touch or no hover is click/tap
206
+ only. One toolbar at a time; Escape closes and returns focus to the heading;
207
+ a pinned toolbar closes on outside pointer or focus leaving.
208
+
209
+ Host extension point: `AppShell` `sectionActions?: Snippet<[ShellSectionActionsContext]>`
210
+ (`{ sectionId, label, custom, editing }`) renders icon buttons in both the
211
+ section overlay and its toolbar (e.g. the planner's Options gear and Help);
212
+ use `ShellIconButton` (from `./workspace`) for matching looks. It renders only
213
+ while editing.
214
+
215
+ `ShellLayoutEditor` no longer has a Placement section (superseded by dragging in
216
+ place); it keeps panels, the navigation sort (icon toggles `aria-pressed` for
217
+ "Show <name> in navigation" / "Show title of <name>"), the preview and Reset.
218
+ The layout helpers and `placeItem`/`resetItem` stay.
219
+
86
220
  ### Activity ticker
87
221
 
88
222
  `ActivityTicker` accepts app-owned `activities: ReadonlyArray<ShellActivity>` plus
@@ -219,11 +353,75 @@ control panel), wired by `app/AppShell.svelte`.
219
353
  `moveItem(id, sectionId, toIndex?)`, `hide(id)`, `show(id)`, `setPanel(edge,
220
354
  { visible?, initial? })`, `reset()`, each returning whether anything changed,
221
355
  plus readers (`layout`, `sections`, `panels`, `applied`, `customized`,
222
- `isHidden`). An assistant calls the same methods the editor does. The
356
+ `isHidden`; item placement is in "Moving items between slots", edit mode in
357
+ "Editing the layout in place"). An assistant calls the same methods the editor does. The
223
358
  context is separate from `useAdminShell()` because `AppShell`, not
224
359
  `AdminShell`, owns the navigation.
360
+ - **Sections belong to the app.** Hosts (and recipes, via the host) suggest
361
+ sections as `ShellNavGroup`s; the user overrides them in the same additive
362
+ version-1 layout: `sections[id] = { label?, showTitle? }` (rename; hide the
363
+ title) and `customSections: { id: 'custom:...', label }[]` (user-created).
364
+ Custom sections join `sectionOrder`, receive items through `moved`, show in
365
+ the editor when empty but not in the nav, and get a unique `custom:` id.
366
+ `showTitle: false` (also settable by a host on `ShellNavGroup.showTitle`)
367
+ renders the items flat in a `role="group"` named by the heading, no
368
+ `<details>`/`<summary>`. `applyShellLayout` keeps the section's original id
369
+ on renamed output groups. Helpers: `renameShellSection`,
370
+ `setShellSectionTitleVisible`, `createShellSection`, `deleteShellSection`
371
+ (custom only; items return to their default sections). Old stored layouts
372
+ need no migration; new host sections and items land in their suggested slot.
373
+ Controller: `renameSection`, `setSectionTitleVisible`, `createSection(label)`
374
+ (returns the id), `deleteSection`.
375
+ - **Item labels.** The same layout renames single navigation entries:
376
+ `items[itemId] = { label? }` (additive; trimmed, blank removed; ids as above,
377
+ top-level items of `nav` and groups). `resolveShellNavModel` items carry
378
+ `label` / `defaultLabel`; `applyShellLayout` emits the renamed item with
379
+ `label` = the user's and `defaultLabel` = the host's (so nav, breadcrumbs and
380
+ titles that read `nav` follow the rename). Helper `renameShellItem(nav, groups,
381
+ layout, itemId, label | null)`; controller `renameItem(itemId, label | null)`
382
+ (null or blank resets). Edit mode: each `ShellNavEditor` row has an icon-only
383
+ "Rename <label>" button opening an inline field (Enter saves, Escape cancels,
384
+ blur saves) and, once renamed, "Reset <label> to <original>"; the original shows
385
+ as the row tooltip. Presets ("cookbooks") ship it in the stored layout.
386
+ - **Sections-only navigation (`navMode: 'sections'`).** `AppShell` (and
387
+ `TenantNav` / `ShellNavEditor` directly) take `navMode?: 'items' | 'sections'`
388
+ (default `'items'`, unchanged). In `'sections'` the left sidebar shows one
389
+ link per section (icon + label), no entries; a collapsed rail (`tenantRail`)
390
+ shows the icons with tooltips. The link goes to `ShellNavGroup.href`, else
391
+ `AppShell` `sectionHref(sectionId)` (user-created sections), else the first
392
+ entry; it is `aria-current="page"` on that page and `"true"` on any of the
393
+ section's entry pages. `AppShell` also takes `iconComponent` for host icon
394
+ names. `ShellNavGroup.icon` / `.href` are additive; the user override is
395
+ `sections[id].icon` (trimmed; blank or the host's icon removes it), helper
396
+ `setShellSectionIcon(nav, groups, layout, id, icon | null)`, controller
397
+ `setSectionIcon(id, icon | null)`; `resolveShellNavModel` sections carry
398
+ `icon` / `defaultIcon` and `applyShellLayout` emits the effective `icon`.
399
+ Icons are shell icon names (`SHELL_SECTION_ICONS` is the picker set, drawn
400
+ from Material icons like the rest of `SHELL_ICON_PATHS`; `SHELL_DEFAULT_SECTION_ICON`
401
+ is `folder`) or host names rendered by `iconComponent` (`ShellSectionIcon`
402
+ tries the built-in set first). Edit mode in this mode: sections keep grip,
403
+ rename, hide, delete; the title toggle is replaced by an "Icon of <label>"
404
+ popover grid ("Use <icon> icon", `aria-pressed` on the current one; Escape
405
+ closes the grid before the toolbar). Entries are not in the sidebar.
406
+ - **`ShellSectionMenu`** (`sectionId`, `controller?`, `meta(entry)`,
407
+ `actions(entry)`, `iconComponent`, `aria-label`, `layout`): the section's page body.
408
+ `layout="cards"` renders an auto-fill grid (min 16rem) of cards: 32px icon in a
409
+ tinted circle, title, `ShellNavItem.description` (2 lines), then `meta` and
410
+ `actions` at the bottom; one stretched link, actions stay separate controls;
411
+ edit mode keeps grip/rename/hide in the grid. Unknown icon names draw the
412
+ default glyph (dev warning), never the name. `layout.items[id].description` (host/preset-set, not editable in the UI)
413
+ overrides an item's `description`. Default `list`: A
414
+ `<ul>` of rows (icon, label link, host `meta`, host `actions`, chevron; the
415
+ row is one stretched link, actions sit above it) in applied order with
416
+ renames; hidden entries are omitted. While editing, the same rows become the
417
+ nav editor's chrome (single-container `Sortable` grip with keyboard moves,
418
+ inline rename/reset, show/hide toggle) driving `moveItem`/`renameItem`/
419
+ `hide`/`show`; rows are not links then. `ShellSectionMenuEntry` is the snippet
420
+ argument (`id, href, label, defaultLabel, icon, hidden, item`).
225
421
  - **`ShellLayoutEditor`**: `controller` (default: context), `preview` (default
226
- true), `iconComponent`. Mount it on a settings page or in a dock tool.
422
+ true), `iconComponent`. Each section has an inline name input, icon toggles
423
+ for visibility and title, and (custom only) a trash button, which confirms
424
+ when non-empty; a New section button creates one. Mount it on a settings page or in a dock tool.
227
425
 
228
426
  ### Sortable and the Board engine
229
427
 
@@ -255,9 +453,8 @@ lives beside, not inside, `./workspace` so the AdminShell barrel stays free of
255
453
  (`{#snippet dock(registry)}`), the instance mounted routes register on
256
454
  when `webmcp` UI is on; pass it to `<AssistantDock {registry} />`. `runtimeDiagnostics` (default false) mounts the
257
455
  read-only `smrt.runtime.diagnostics.read` WebMCP tool. `dockToggles`
258
- (`{ tool, label, icon? }[]`) renders icon buttons at the right of the shell
259
- header (the AdminShell `header` row, shown only when the prop is non-empty),
260
- each toggling the `ShellDockTool` with that id: `aria-pressed` and
456
+ (`{ tool, label, icon?, slot? }[]`) renders icon buttons in the shell slot
457
+ named by `slot` (default `header.end`; see "Regions and slots"), each toggling the `ShellDockTool` with that id: `aria-pressed` and
261
458
  `aria-expanded` follow the dock, `aria-controls` is
262
459
  `smrt-admin-shell-right-panel`, the label is the tooltip, and `assistant`
263
460
  defaults to a chat-bubble icon (`icon: 'chat'`; other text is a glyph). A
@@ -1 +1 @@
1
- {"version":3,"file":"dictation-source.d.ts","sourceRoot":"","sources":["../../../../src/browser-ai/adapters/stt/dictation-source.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,aAA0C,GAClD,MAAM,OAAO,CAAC,UAAU,CAAC,CAc3B"}
1
+ {"version":3,"file":"dictation-source.d.ts","sourceRoot":"","sources":["../../../../src/browser-ai/adapters/stt/dictation-source.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,aAA0C,GAClD,MAAM,OAAO,CAAC,UAAU,CAAC,CAmB3B"}
@@ -7,7 +7,8 @@
7
7
  * adapter lazily, once, the first time someone starts dictating: nothing
8
8
  * loads and no microphone prompt appears until then. Defaults to the
9
9
  * browser's own speech recognition (`browser-speech`), which needs no
10
- * download; an unsupported browser rejects with
10
+ * download; an on-device model is never downloaded by dictation (see
11
+ * `LocalSpeechSTTAdapter.prepare`). An unsupported browser rejects with
11
12
  * `CapabilityNotAvailableError`, which `Dictation` reports in plain words.
12
13
  *
13
14
  * @example
@@ -26,7 +27,12 @@ export function createSttDictationSource(options = { type: 'browser-speech' }) {
26
27
  return () => {
27
28
  adapter ??= (async () => {
28
29
  const created = await getSTT(options);
29
- await created.ensureInitialized();
30
+ // An adapter that needs a download is never loaded here: dictation must
31
+ // not start one. It checks its own model when started, and the host
32
+ // loads it explicitly (after asking).
33
+ if (!created.getCapabilities().requiresDownload) {
34
+ await created.ensureInitialized();
35
+ }
30
36
  return created;
31
37
  })().catch((error) => {
32
38
  // Let a later tap try again (for example after a permission change).
@@ -20,8 +20,11 @@ import type { GetSTTOptions, STTAdapter } from './types.js';
20
20
  * // Whisper.cpp (recommended for accuracy)
21
21
  * const stt = await getSTT({ type: 'whisper-cpp', model: 'tiny.en' });
22
22
  *
23
- * // Whisper WASM (transformers.js - has known issues)
24
- * const stt = await getSTT({ type: 'whisper-wasm', modelSize: 'tiny' });
23
+ * // Local Whisper (transformers.js; WebGPU or WASM, one-time ~45 MB download)
24
+ * const stt = await getSTT({ type: 'whisper-local' });
25
+ *
26
+ * // Moonshine (fastest for live dictation, one-time ~32 MB download)
27
+ * const stt = await getSTT({ type: 'moonshine' });
25
28
  * ```
26
29
  */
27
30
  export declare function getSTT(options?: GetSTTOptions): Promise<STTAdapter>;
@@ -45,5 +48,5 @@ export declare function getSTTAuto(options?: Partial<Omit<GetSTTOptions, 'type'>
45
48
  /**
46
49
  * Check if a specific STT backend is available
47
50
  */
48
- export declare function isSTTAvailable(type: 'browser-speech' | 'whisper-wasm'): boolean;
51
+ export declare function isSTTAvailable(type: 'browser-speech' | 'whisper-wasm' | 'whisper-local' | 'moonshine'): boolean;
49
52
  //# sourceMappingURL=factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/browser-ai/adapters/stt/factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAEV,aAAa,EACb,UAAU,EAGX,MAAM,YAAY,CAAC;AA6BpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAqB7E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAM,GACjD,OAAO,CAAC,UAAU,CAAC,CAmBrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,gBAAgB,GAAG,cAAc,GACtC,OAAO,CAYT"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/browser-ai/adapters/stt/factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAEV,aAAa,EAEb,UAAU,EAEX,MAAM,YAAY,CAAC;AAkCpB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAuB7E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAM,GACjD,OAAO,CAAC,UAAU,CAAC,CAmBrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,gBAAgB,GAAG,cAAc,GAAG,eAAe,GAAG,WAAW,GACtE,OAAO,CAgBT"}