@happyvertical/smrt-svelte 0.30.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 (357) hide show
  1. package/AGENTS.md +317 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +185 -0
  5. package/dist/Provider.svelte +204 -0
  6. package/dist/Provider.svelte.d.ts +73 -0
  7. package/dist/Provider.svelte.d.ts.map +1 -0
  8. package/dist/__tests__/app-state.test.js +156 -0
  9. package/dist/__tests__/warm-clients.test.js +186 -0
  10. package/dist/browser-ai/adapters/llm/factory.d.ts +38 -0
  11. package/dist/browser-ai/adapters/llm/factory.d.ts.map +1 -0
  12. package/dist/browser-ai/adapters/llm/factory.js +91 -0
  13. package/dist/browser-ai/adapters/llm/index.d.ts +7 -0
  14. package/dist/browser-ai/adapters/llm/index.d.ts.map +1 -0
  15. package/dist/browser-ai/adapters/llm/index.js +6 -0
  16. package/dist/browser-ai/adapters/llm/types.d.ts +182 -0
  17. package/dist/browser-ai/adapters/llm/types.d.ts.map +1 -0
  18. package/dist/browser-ai/adapters/llm/types.js +43 -0
  19. package/dist/browser-ai/adapters/llm/webllm.d.ts +33 -0
  20. package/dist/browser-ai/adapters/llm/webllm.d.ts.map +1 -0
  21. package/dist/browser-ai/adapters/llm/webllm.js +225 -0
  22. package/dist/browser-ai/adapters/stt/browser-speech.d.ts +31 -0
  23. package/dist/browser-ai/adapters/stt/browser-speech.d.ts.map +1 -0
  24. package/dist/browser-ai/adapters/stt/browser-speech.js +217 -0
  25. package/dist/browser-ai/adapters/stt/factory.d.ts +49 -0
  26. package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -0
  27. package/dist/browser-ai/adapters/stt/factory.js +110 -0
  28. package/dist/browser-ai/adapters/stt/index.d.ts +9 -0
  29. package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -0
  30. package/dist/browser-ai/adapters/stt/index.js +8 -0
  31. package/dist/browser-ai/adapters/stt/types.d.ts +154 -0
  32. package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -0
  33. package/dist/browser-ai/adapters/stt/types.js +4 -0
  34. package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts +46 -0
  35. package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts.map +1 -0
  36. package/dist/browser-ai/adapters/stt/whisper-cpp.js +348 -0
  37. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +51 -0
  38. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +1 -0
  39. package/dist/browser-ai/adapters/stt/whisper-wasm.js +380 -0
  40. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +42 -0
  41. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -0
  42. package/dist/browser-ai/adapters/tts/browser-synthesis.js +235 -0
  43. package/dist/browser-ai/adapters/tts/factory.d.ts +53 -0
  44. package/dist/browser-ai/adapters/tts/factory.d.ts.map +1 -0
  45. package/dist/browser-ai/adapters/tts/factory.js +92 -0
  46. package/dist/browser-ai/adapters/tts/index.d.ts +7 -0
  47. package/dist/browser-ai/adapters/tts/index.d.ts.map +1 -0
  48. package/dist/browser-ai/adapters/tts/index.js +6 -0
  49. package/dist/browser-ai/adapters/tts/types.d.ts +140 -0
  50. package/dist/browser-ai/adapters/tts/types.d.ts.map +1 -0
  51. package/dist/browser-ai/adapters/tts/types.js +4 -0
  52. package/dist/browser-ai/capabilities/detector.d.ts +38 -0
  53. package/dist/browser-ai/capabilities/detector.d.ts.map +1 -0
  54. package/dist/browser-ai/capabilities/detector.js +211 -0
  55. package/dist/browser-ai/core/errors.d.ts +62 -0
  56. package/dist/browser-ai/core/errors.d.ts.map +1 -0
  57. package/dist/browser-ai/core/errors.js +92 -0
  58. package/dist/browser-ai/core/index.d.ts +6 -0
  59. package/dist/browser-ai/core/index.d.ts.map +1 -0
  60. package/dist/browser-ai/core/index.js +5 -0
  61. package/dist/browser-ai/core/types.d.ts +115 -0
  62. package/dist/browser-ai/core/types.d.ts.map +1 -0
  63. package/dist/browser-ai/core/types.js +34 -0
  64. package/dist/browser-ai/index.d.ts +12 -0
  65. package/dist/browser-ai/index.d.ts.map +1 -0
  66. package/dist/browser-ai/index.js +16 -0
  67. package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte +77 -0
  68. package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts +16 -0
  69. package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts.map +1 -0
  70. package/dist/browser-ai/svelte/components/CapabilityGate.svelte +57 -0
  71. package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts +15 -0
  72. package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts.map +1 -0
  73. package/dist/browser-ai/svelte/components/DownloadProgress.svelte +141 -0
  74. package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts +15 -0
  75. package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts.map +1 -0
  76. package/dist/browser-ai/svelte/components/STTTest.svelte +379 -0
  77. package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts +9 -0
  78. package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts.map +1 -0
  79. package/dist/browser-ai/svelte/components/VoiceInput.svelte +200 -0
  80. package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts +16 -0
  81. package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts.map +1 -0
  82. package/dist/browser-ai/svelte/index.d.ts +15 -0
  83. package/dist/browser-ai/svelte/index.d.ts.map +1 -0
  84. package/dist/browser-ai/svelte/index.js +28 -0
  85. package/dist/browser-ai/ui.d.ts +16 -0
  86. package/dist/browser-ai/ui.d.ts.map +1 -0
  87. package/dist/browser-ai/ui.js +67 -0
  88. package/dist/components/admin/AgentAdminPanel.svelte +111 -0
  89. package/dist/components/admin/AgentAdminPanel.svelte.d.ts +25 -0
  90. package/dist/components/admin/AgentAdminPanel.svelte.d.ts.map +1 -0
  91. package/dist/components/admin/AgentAdminTabs.svelte +280 -0
  92. package/dist/components/admin/AgentAdminTabs.svelte.d.ts +23 -0
  93. package/dist/components/admin/AgentAdminTabs.svelte.d.ts.map +1 -0
  94. package/dist/components/admin/AgentSettingsShell.svelte +257 -0
  95. package/dist/components/admin/AgentSettingsShell.svelte.d.ts +33 -0
  96. package/dist/components/admin/AgentSettingsShell.svelte.d.ts.map +1 -0
  97. package/dist/components/admin/index.d.ts +5 -0
  98. package/dist/components/admin/index.d.ts.map +1 -0
  99. package/dist/components/admin/index.js +6 -0
  100. package/dist/components/forms/AddressInput.svelte +500 -0
  101. package/dist/components/forms/AddressInput.svelte.d.ts +36 -0
  102. package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -0
  103. package/dist/components/forms/CheckboxInput.svelte +208 -0
  104. package/dist/components/forms/CheckboxInput.svelte.d.ts +20 -0
  105. package/dist/components/forms/CheckboxInput.svelte.d.ts.map +1 -0
  106. package/dist/components/forms/DateRangeInput.svelte +628 -0
  107. package/dist/components/forms/DateRangeInput.svelte.d.ts +33 -0
  108. package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -0
  109. package/dist/components/forms/DateTimeInput.svelte +521 -0
  110. package/dist/components/forms/DateTimeInput.svelte.d.ts +24 -0
  111. package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -0
  112. package/dist/components/forms/FileUpload.svelte +358 -0
  113. package/dist/components/forms/FileUpload.svelte.d.ts +22 -0
  114. package/dist/components/forms/FileUpload.svelte.d.ts.map +1 -0
  115. package/dist/components/forms/Form.svelte +771 -0
  116. package/dist/components/forms/Form.svelte.d.ts +26 -0
  117. package/dist/components/forms/Form.svelte.d.ts.map +1 -0
  118. package/dist/components/forms/FormGroup.svelte +86 -0
  119. package/dist/components/forms/FormGroup.svelte.d.ts +13 -0
  120. package/dist/components/forms/FormGroup.svelte.d.ts.map +1 -0
  121. package/dist/components/forms/FormMicButton.svelte +179 -0
  122. package/dist/components/forms/FormMicButton.svelte.d.ts +10 -0
  123. package/dist/components/forms/FormMicButton.svelte.d.ts.map +1 -0
  124. package/dist/components/forms/Input.svelte +83 -0
  125. package/dist/components/forms/Input.svelte.d.ts +9 -0
  126. package/dist/components/forms/Input.svelte.d.ts.map +1 -0
  127. package/dist/components/forms/MeasurementInput.svelte +505 -0
  128. package/dist/components/forms/MeasurementInput.svelte.d.ts +35 -0
  129. package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -0
  130. package/dist/components/forms/MoneyInput.svelte +412 -0
  131. package/dist/components/forms/MoneyInput.svelte.d.ts +30 -0
  132. package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -0
  133. package/dist/components/forms/NumberInput.svelte +310 -0
  134. package/dist/components/forms/NumberInput.svelte.d.ts +28 -0
  135. package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -0
  136. package/dist/components/forms/PhoneInput.svelte +530 -0
  137. package/dist/components/forms/PhoneInput.svelte.d.ts +22 -0
  138. package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -0
  139. package/dist/components/forms/SearchInput.svelte +358 -0
  140. package/dist/components/forms/SearchInput.svelte.d.ts +33 -0
  141. package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
  142. package/dist/components/forms/Select.svelte +83 -0
  143. package/dist/components/forms/Select.svelte.d.ts +11 -0
  144. package/dist/components/forms/Select.svelte.d.ts.map +1 -0
  145. package/dist/components/forms/SelectInput.svelte +254 -0
  146. package/dist/components/forms/SelectInput.svelte.d.ts +25 -0
  147. package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -0
  148. package/dist/components/forms/TextInput.svelte +415 -0
  149. package/dist/components/forms/TextInput.svelte.d.ts +26 -0
  150. package/dist/components/forms/TextInput.svelte.d.ts.map +1 -0
  151. package/dist/components/forms/Textarea.svelte +85 -0
  152. package/dist/components/forms/Textarea.svelte.d.ts +10 -0
  153. package/dist/components/forms/Textarea.svelte.d.ts.map +1 -0
  154. package/dist/components/forms/TextareaInput.svelte +386 -0
  155. package/dist/components/forms/TextareaInput.svelte.d.ts +26 -0
  156. package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -0
  157. package/dist/components/forms/Toggle.svelte +217 -0
  158. package/dist/components/forms/Toggle.svelte.d.ts +37 -0
  159. package/dist/components/forms/Toggle.svelte.d.ts.map +1 -0
  160. package/dist/components/forms/__tests__/AddressInput.behavior.test.js +122 -0
  161. package/dist/components/forms/__tests__/CheckboxInput.test.js +92 -0
  162. package/dist/components/forms/__tests__/DateRangeInput.behavior.test.js +135 -0
  163. package/dist/components/forms/__tests__/DateTimeInput.behavior.test.js +103 -0
  164. package/dist/components/forms/__tests__/FileUpload.test.js +90 -0
  165. package/dist/components/forms/__tests__/Form.behavior.test.js +137 -0
  166. package/dist/components/forms/__tests__/Form.test.js +58 -0
  167. package/dist/components/forms/__tests__/FormGroup.test.js +48 -0
  168. package/dist/components/forms/__tests__/FormMicButton.test.js +86 -0
  169. package/dist/components/forms/__tests__/Input.test.js +49 -0
  170. package/dist/components/forms/__tests__/MeasurementInput.behavior.test.js +129 -0
  171. package/dist/components/forms/__tests__/MoneyInput.behavior.test.js +124 -0
  172. package/dist/components/forms/__tests__/NumberInput.behavior.test.js +141 -0
  173. package/dist/components/forms/__tests__/PhoneInput.behavior.test.js +96 -0
  174. package/dist/components/forms/__tests__/SearchInput.test.js +79 -0
  175. package/dist/components/forms/__tests__/Select.test.js +37 -0
  176. package/dist/components/forms/__tests__/SelectInput.behavior.test.js +132 -0
  177. package/dist/components/forms/__tests__/TextInput.behavior.test.js +131 -0
  178. package/dist/components/forms/__tests__/Textarea.test.js +39 -0
  179. package/dist/components/forms/__tests__/TextareaInput.behavior.test.js +96 -0
  180. package/dist/components/forms/__tests__/Toggle.test.js +87 -0
  181. package/dist/components/forms/__tests__/composite-inputs-a11y.test.js +69 -0
  182. package/dist/components/forms/__tests__/form-group-input.fixture.svelte +16 -0
  183. package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts +9 -0
  184. package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts.map +1 -0
  185. package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +33 -0
  186. package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +12 -0
  187. package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +1 -0
  188. package/dist/components/forms/__tests__/rich-inputs-a11y.test.js +87 -0
  189. package/dist/components/forms/index.d.ts +25 -0
  190. package/dist/components/forms/index.d.ts.map +1 -0
  191. package/dist/components/forms/index.js +25 -0
  192. package/dist/components/forms/types.d.ts +33 -0
  193. package/dist/components/forms/types.d.ts.map +1 -0
  194. package/dist/components/forms/types.js +4 -0
  195. package/dist/components/module/ModulePanel.svelte +134 -0
  196. package/dist/components/module/ModulePanel.svelte.d.ts +22 -0
  197. package/dist/components/module/ModulePanel.svelte.d.ts.map +1 -0
  198. package/dist/components/module/index.d.ts +5 -0
  199. package/dist/components/module/index.d.ts.map +1 -0
  200. package/dist/components/module/index.js +4 -0
  201. package/dist/components/workspace/Breadcrumbs.svelte +141 -0
  202. package/dist/components/workspace/Breadcrumbs.svelte.d.ts +21 -0
  203. package/dist/components/workspace/Breadcrumbs.svelte.d.ts.map +1 -0
  204. package/dist/components/workspace/NavTree.svelte +354 -0
  205. package/dist/components/workspace/NavTree.svelte.d.ts +45 -0
  206. package/dist/components/workspace/NavTree.svelte.d.ts.map +1 -0
  207. package/dist/components/workspace/README.md +34 -0
  208. package/dist/components/workspace/RoleShell.svelte +309 -0
  209. package/dist/components/workspace/RoleShell.svelte.d.ts +91 -0
  210. package/dist/components/workspace/RoleShell.svelte.d.ts.map +1 -0
  211. package/dist/components/workspace/WorkspaceShell.svelte +951 -0
  212. package/dist/components/workspace/WorkspaceShell.svelte.d.ts +112 -0
  213. package/dist/components/workspace/WorkspaceShell.svelte.d.ts.map +1 -0
  214. package/dist/components/workspace/__tests__/RoleShell.test.js +772 -0
  215. package/dist/components/workspace/__tests__/WorkspaceShell.test.js +630 -0
  216. package/dist/components/workspace/__tests__/breadcrumbs-helpers.test.js +141 -0
  217. package/dist/components/workspace/__tests__/context-forwarding-harness.svelte +45 -0
  218. package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts +21 -0
  219. package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts.map +1 -0
  220. package/dist/components/workspace/__tests__/define-tools-dock.test.js +1010 -0
  221. package/dist/components/workspace/__tests__/harness.svelte +25 -0
  222. package/dist/components/workspace/__tests__/harness.svelte.d.ts +14 -0
  223. package/dist/components/workspace/__tests__/harness.svelte.d.ts.map +1 -0
  224. package/dist/components/workspace/__tests__/index.test.js +37 -0
  225. package/dist/components/workspace/__tests__/manifest-nav-helpers.test.js +24 -0
  226. package/dist/components/workspace/__tests__/manifest-nav.test.js +599 -0
  227. package/dist/components/workspace/__tests__/nav-helpers.test.js +95 -0
  228. package/dist/components/workspace/__tests__/render-harness.svelte +66 -0
  229. package/dist/components/workspace/__tests__/render-harness.svelte.d.ts +32 -0
  230. package/dist/components/workspace/__tests__/render-harness.svelte.d.ts.map +1 -0
  231. package/dist/components/workspace/__tests__/render-tools-dock.test.js +243 -0
  232. package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte +58 -0
  233. package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts +16 -0
  234. package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts.map +1 -0
  235. package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte +41 -0
  236. package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts +13 -0
  237. package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts.map +1 -0
  238. package/dist/components/workspace/__tests__/test-icon.svelte +17 -0
  239. package/dist/components/workspace/__tests__/test-icon.svelte.d.ts +19 -0
  240. package/dist/components/workspace/__tests__/test-icon.svelte.d.ts.map +1 -0
  241. package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte +38 -0
  242. package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts +22 -0
  243. package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts.map +1 -0
  244. package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts +65 -0
  245. package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts.map +1 -0
  246. package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.js +115 -0
  247. package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts +15 -0
  248. package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts.map +1 -0
  249. package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.js +7 -0
  250. package/dist/components/workspace/__tests__/typed-tool-fixture.test.js +115 -0
  251. package/dist/components/workspace/__tests__/use-harness-orphan.svelte +9 -0
  252. package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts +19 -0
  253. package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts.map +1 -0
  254. package/dist/components/workspace/__tests__/use-harness.svelte +23 -0
  255. package/dist/components/workspace/__tests__/use-harness.svelte.d.ts +8 -0
  256. package/dist/components/workspace/__tests__/use-harness.svelte.d.ts.map +1 -0
  257. package/dist/components/workspace/__tests__/use-tools-dock.test.js +33 -0
  258. package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte +43 -0
  259. package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts +11 -0
  260. package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts.map +1 -0
  261. package/dist/components/workspace/breadcrumbs-helpers.d.ts +44 -0
  262. package/dist/components/workspace/breadcrumbs-helpers.d.ts.map +1 -0
  263. package/dist/components/workspace/breadcrumbs-helpers.js +88 -0
  264. package/dist/components/workspace/index.d.ts +16 -0
  265. package/dist/components/workspace/index.d.ts.map +1 -0
  266. package/dist/components/workspace/index.js +14 -0
  267. package/dist/components/workspace/manifest-nav.d.ts +200 -0
  268. package/dist/components/workspace/manifest-nav.d.ts.map +1 -0
  269. package/dist/components/workspace/manifest-nav.js +408 -0
  270. package/dist/components/workspace/nav-helpers.d.ts +36 -0
  271. package/dist/components/workspace/nav-helpers.d.ts.map +1 -0
  272. package/dist/components/workspace/nav-helpers.js +60 -0
  273. package/dist/components/workspace/server/__tests__/compose-availability.test.js +383 -0
  274. package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts +78 -0
  275. package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts.map +1 -0
  276. package/dist/components/workspace/server/__tests__/typed-context-fixture.js +104 -0
  277. package/dist/components/workspace/server/compose-availability.d.ts +73 -0
  278. package/dist/components/workspace/server/compose-availability.d.ts.map +1 -0
  279. package/dist/components/workspace/server/compose-availability.js +114 -0
  280. package/dist/components/workspace/server/index.d.ts +13 -0
  281. package/dist/components/workspace/server/index.d.ts.map +1 -0
  282. package/dist/components/workspace/server/index.js +11 -0
  283. package/dist/components/workspace/server/types.d.ts +108 -0
  284. package/dist/components/workspace/server/types.d.ts.map +1 -0
  285. package/dist/components/workspace/server/types.js +11 -0
  286. package/dist/components/workspace/tools-dock/ToolsDock.svelte +565 -0
  287. package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts +14 -0
  288. package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts.map +1 -0
  289. package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts +143 -0
  290. package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts.map +1 -0
  291. package/dist/components/workspace/tools-dock/define-tools-dock.svelte.js +487 -0
  292. package/dist/components/workspace/tools-dock/use-tools-dock.d.ts +41 -0
  293. package/dist/components/workspace/tools-dock/use-tools-dock.d.ts.map +1 -0
  294. package/dist/components/workspace/tools-dock/use-tools-dock.js +50 -0
  295. package/dist/components/workspace/types.d.ts +372 -0
  296. package/dist/components/workspace/types.d.ts.map +1 -0
  297. package/dist/components/workspace/types.js +6 -0
  298. package/dist/hooks/index.d.ts +11 -0
  299. package/dist/hooks/index.d.ts.map +1 -0
  300. package/dist/hooks/index.js +10 -0
  301. package/dist/hooks/useAppState.svelte.d.ts +46 -0
  302. package/dist/hooks/useAppState.svelte.d.ts.map +1 -0
  303. package/dist/hooks/useAppState.svelte.js +59 -0
  304. package/dist/hooks/useAuth.svelte.d.ts +41 -0
  305. package/dist/hooks/useAuth.svelte.d.ts.map +1 -0
  306. package/dist/hooks/useAuth.svelte.js +43 -0
  307. package/dist/hooks/useLLM.svelte.d.ts +69 -0
  308. package/dist/hooks/useLLM.svelte.d.ts.map +1 -0
  309. package/dist/hooks/useLLM.svelte.js +85 -0
  310. package/dist/hooks/useSTT.svelte.d.ts +68 -0
  311. package/dist/hooks/useSTT.svelte.d.ts.map +1 -0
  312. package/dist/hooks/useSTT.svelte.js +97 -0
  313. package/dist/hooks/useSocket.svelte.d.ts +45 -0
  314. package/dist/hooks/useSocket.svelte.d.ts.map +1 -0
  315. package/dist/hooks/useSocket.svelte.js +54 -0
  316. package/dist/hooks/useTTS.svelte.d.ts +65 -0
  317. package/dist/hooks/useTTS.svelte.d.ts.map +1 -0
  318. package/dist/hooks/useTTS.svelte.js +93 -0
  319. package/dist/hooks/useTheme.d.ts +13 -0
  320. package/dist/hooks/useTheme.d.ts.map +1 -0
  321. package/dist/hooks/useTheme.js +16 -0
  322. package/dist/i18n/__tests__/server.spec.js +50 -0
  323. package/dist/i18n/server.d.ts +47 -0
  324. package/dist/i18n/server.d.ts.map +1 -0
  325. package/dist/i18n/server.js +58 -0
  326. package/dist/i18n/strings.forms.d.ts +33 -0
  327. package/dist/i18n/strings.forms.d.ts.map +1 -0
  328. package/dist/i18n/strings.forms.js +54 -0
  329. package/dist/i18n/strings.workspace.d.ts +34 -0
  330. package/dist/i18n/strings.workspace.d.ts.map +1 -0
  331. package/dist/i18n/strings.workspace.js +40 -0
  332. package/dist/index.d.ts +18 -0
  333. package/dist/index.d.ts.map +1 -0
  334. package/dist/index.js +23 -0
  335. package/dist/state/__tests__/warm-clients.test.js +40 -0
  336. package/dist/state/app-state.d.ts +308 -0
  337. package/dist/state/app-state.d.ts.map +1 -0
  338. package/dist/state/app-state.js +64 -0
  339. package/dist/state/app-state.svelte.d.ts +196 -0
  340. package/dist/state/app-state.svelte.d.ts.map +1 -0
  341. package/dist/state/app-state.svelte.js +774 -0
  342. package/dist/state/context.d.ts +23 -0
  343. package/dist/state/context.d.ts.map +1 -0
  344. package/dist/state/context.js +32 -0
  345. package/dist/state/form-context.d.ts +59 -0
  346. package/dist/state/form-context.d.ts.map +1 -0
  347. package/dist/state/form-context.js +31 -0
  348. package/dist/state/form-group-context.d.ts +13 -0
  349. package/dist/state/form-group-context.d.ts.map +1 -0
  350. package/dist/state/form-group-context.js +28 -0
  351. package/dist/state/index.d.ts +9 -0
  352. package/dist/state/index.d.ts.map +1 -0
  353. package/dist/state/index.js +8 -0
  354. package/dist/state/warm-clients.d.ts +136 -0
  355. package/dist/state/warm-clients.d.ts.map +1 -0
  356. package/dist/state/warm-clients.js +231 -0
  357. package/package.json +137 -0
@@ -0,0 +1,383 @@
1
+ /**
2
+ * Tests for the server-side dock availability gate composer
3
+ * (happyvertical/smrt#1226 Phase 4c).
4
+ *
5
+ * Covers:
6
+ * - tools without `gates` are unconditionally included (back-compat)
7
+ * - single passing / failing gate
8
+ * - AND semantics across multiple gates
9
+ * - sync and async evaluators
10
+ * - unknown-prefix error message (loud-fail)
11
+ * - context pass-through
12
+ * - edge cases (empty arrays / maps)
13
+ * - label / badge passthrough into AvailableTool
14
+ */
15
+ import { describe, expect, it, vi } from 'vitest';
16
+ import { composeDockAvailability } from '../compose-availability.js';
17
+ const alwaysTrue = () => true;
18
+ const alwaysFalse = () => false;
19
+ const asyncTrue = async () => true;
20
+ const asyncFalse = async () => false;
21
+ describe('composeDockAvailability', () => {
22
+ it('includes tools without a `gates` field unconditionally', async () => {
23
+ const result = await composeDockAvailability({
24
+ tools: [{ id: 'chat', label: 'Chat' }],
25
+ context: {},
26
+ evaluators: {},
27
+ });
28
+ expect(result).toHaveLength(1);
29
+ expect(result[0]?.id).toBe('chat');
30
+ });
31
+ it('includes tools with an empty `gates` array unconditionally', async () => {
32
+ const result = await composeDockAvailability({
33
+ tools: [{ id: 'chat', label: 'Chat', gates: [] }],
34
+ context: {},
35
+ evaluators: {},
36
+ });
37
+ expect(result).toHaveLength(1);
38
+ expect(result[0]?.id).toBe('chat');
39
+ });
40
+ it('includes a tool whose single gate evaluates to true', async () => {
41
+ const result = await composeDockAvailability({
42
+ tools: [{ id: 'video', label: 'Video', gates: ['feature:video-tools'] }],
43
+ context: {},
44
+ evaluators: { feature: alwaysTrue },
45
+ });
46
+ expect(result).toHaveLength(1);
47
+ expect(result[0]?.id).toBe('video');
48
+ });
49
+ it('excludes a tool whose single gate evaluates to false', async () => {
50
+ const result = await composeDockAvailability({
51
+ tools: [{ id: 'video', label: 'Video', gates: ['feature:video-tools'] }],
52
+ context: {},
53
+ evaluators: { feature: alwaysFalse },
54
+ });
55
+ expect(result).toEqual([]);
56
+ });
57
+ it('requires ALL gates to pass (AND semantics)', async () => {
58
+ const result = await composeDockAvailability({
59
+ tools: [
60
+ {
61
+ id: 'restricted',
62
+ label: 'Restricted',
63
+ gates: ['permission:foo', 'feature:bar'],
64
+ },
65
+ ],
66
+ context: {},
67
+ evaluators: { permission: alwaysTrue, feature: alwaysFalse },
68
+ });
69
+ expect(result).toEqual([]);
70
+ });
71
+ it('includes a tool only when EVERY gate passes', async () => {
72
+ const result = await composeDockAvailability({
73
+ tools: [
74
+ {
75
+ id: 'allowed',
76
+ label: 'Allowed',
77
+ gates: ['permission:foo', 'feature:bar'],
78
+ },
79
+ ],
80
+ context: {},
81
+ evaluators: { permission: alwaysTrue, feature: asyncTrue },
82
+ });
83
+ expect(result).toHaveLength(1);
84
+ expect(result[0]?.id).toBe('allowed');
85
+ });
86
+ it('accepts sync evaluators that return a plain boolean', async () => {
87
+ const result = await composeDockAvailability({
88
+ tools: [{ id: 't', label: 'T', gates: ['x:y'] }],
89
+ context: {},
90
+ evaluators: { x: (_id, _ctx) => true },
91
+ });
92
+ expect(result).toHaveLength(1);
93
+ });
94
+ it('accepts async evaluators that return a Promise<boolean>', async () => {
95
+ const result = await composeDockAvailability({
96
+ tools: [{ id: 't', label: 'T', gates: ['x:y'] }],
97
+ context: {},
98
+ evaluators: { x: async () => true },
99
+ });
100
+ expect(result).toHaveLength(1);
101
+ });
102
+ it('throws with a clear message when a gate prefix has no evaluator', async () => {
103
+ await expect(composeDockAvailability({
104
+ tools: [
105
+ { id: 'video', label: 'Video', gates: ['feature:video-tools'] },
106
+ ],
107
+ context: {},
108
+ evaluators: { permission: alwaysTrue },
109
+ })).rejects.toThrow(/No evaluator registered for gate prefix "feature".*tool "video".*gate "feature:video-tools".*Available prefixes: permission/);
110
+ });
111
+ it('reports `(none)` for available prefixes when the evaluators map is empty', async () => {
112
+ await expect(composeDockAvailability({
113
+ tools: [
114
+ { id: 'video', label: 'Video', gates: ['feature:video-tools'] },
115
+ ],
116
+ context: {},
117
+ evaluators: {},
118
+ })).rejects.toThrow(/Available prefixes: \(none\)/);
119
+ });
120
+ it('passes the supplied `context` through to each evaluator', async () => {
121
+ const ctx = { userId: 'u-1', tenantId: 't-1' };
122
+ const permission = vi.fn(() => true);
123
+ const feature = vi.fn(() => true);
124
+ await composeDockAvailability({
125
+ tools: [
126
+ {
127
+ id: 'tool',
128
+ label: 'Tool',
129
+ gates: ['permission:articles.publish', 'feature:video-tools'],
130
+ },
131
+ ],
132
+ context: ctx,
133
+ evaluators: { permission, feature },
134
+ });
135
+ expect(permission).toHaveBeenCalledWith('permission:articles.publish', ctx);
136
+ expect(feature).toHaveBeenCalledWith('feature:video-tools', ctx);
137
+ });
138
+ it('returns an empty array for an empty `tools` input', async () => {
139
+ const result = await composeDockAvailability({
140
+ tools: [],
141
+ context: {},
142
+ evaluators: {},
143
+ });
144
+ expect(result).toEqual([]);
145
+ });
146
+ it('handles an empty `evaluators` map fine when no tools have gates', async () => {
147
+ const result = await composeDockAvailability({
148
+ tools: [
149
+ { id: 'a', label: 'A' },
150
+ { id: 'b', label: 'B' },
151
+ ],
152
+ context: {},
153
+ evaluators: {},
154
+ });
155
+ expect(result.map((t) => t.id)).toEqual(['a', 'b']);
156
+ });
157
+ it('passes through `label` and `badge` from the tool def to AvailableTool', async () => {
158
+ const tools = [
159
+ { id: 'inbox', label: 'Inbox', badge: 3 },
160
+ { id: 'tasks', label: 'Tasks', badge: 'new' },
161
+ { id: 'plain', label: 'Plain' }, // no badge → omitted in output
162
+ ];
163
+ const result = await composeDockAvailability({
164
+ tools,
165
+ context: {},
166
+ evaluators: {},
167
+ });
168
+ expect(result).toEqual([
169
+ { id: 'inbox', label: 'Inbox', badge: 3 },
170
+ { id: 'tasks', label: 'Tasks', badge: 'new' },
171
+ { id: 'plain', label: 'Plain' },
172
+ ]);
173
+ });
174
+ it('omits a missing `label` from the AvailableTool result (lets the dock fall back)', async () => {
175
+ const result = await composeDockAvailability({
176
+ tools: [{ id: 'no-label' }],
177
+ context: {},
178
+ evaluators: {},
179
+ });
180
+ // No `label` key at all — `defineToolsDock.applyAvailability` falls
181
+ // back to the registered ToolDef metadata.
182
+ expect(result[0]).toEqual({ id: 'no-label' });
183
+ expect(result[0]).not.toHaveProperty('label');
184
+ expect(result[0]).not.toHaveProperty('badge');
185
+ });
186
+ it('omits `badge` when the tool def has no badge (no implicit clear)', async () => {
187
+ const result = await composeDockAvailability({
188
+ tools: [{ id: 'chat', label: 'Chat', gates: [] }],
189
+ context: {},
190
+ evaluators: {},
191
+ });
192
+ // The dock treats `badge: null` as an explicit clear of the
193
+ // registered default badge. Absence must remain absence.
194
+ expect(result[0]).toEqual({ id: 'chat', label: 'Chat' });
195
+ expect(result[0]).not.toHaveProperty('badge');
196
+ });
197
+ it('preserves explicit `badge: null` when the caller does set it', async () => {
198
+ const result = await composeDockAvailability({
199
+ tools: [{ id: 'reset', label: 'Reset', badge: null }],
200
+ context: {},
201
+ evaluators: {},
202
+ });
203
+ expect(result[0]).toEqual({ id: 'reset', label: 'Reset', badge: null });
204
+ });
205
+ it('filters a mixed input correctly (gated + ungated, pass + fail)', async () => {
206
+ const result = await composeDockAvailability({
207
+ tools: [
208
+ { id: 'always', label: 'Always' },
209
+ { id: 'allowed', label: 'Allowed', gates: ['permission:foo'] },
210
+ { id: 'denied', label: 'Denied', gates: ['permission:bar'] },
211
+ { id: 'flagged', label: 'Flagged', gates: ['feature:on'] },
212
+ ],
213
+ context: { userId: 'u-1' },
214
+ evaluators: {
215
+ permission: async (id) => id === 'permission:foo',
216
+ feature: asyncTrue,
217
+ },
218
+ });
219
+ expect(result.map((t) => t.id)).toEqual(['always', 'allowed', 'flagged']);
220
+ });
221
+ it('still throws on unknown prefix even when other gates on the same tool would have passed', async () => {
222
+ await expect(composeDockAvailability({
223
+ tools: [
224
+ {
225
+ id: 'mixed',
226
+ label: 'Mixed',
227
+ gates: ['permission:ok', 'mystery:??'],
228
+ },
229
+ ],
230
+ context: {},
231
+ evaluators: { permission: alwaysTrue },
232
+ })).rejects.toThrow(/gate "mystery:\?\?"/);
233
+ });
234
+ it('treats async evaluator rejections as errors (does not swallow)', async () => {
235
+ await expect(composeDockAvailability({
236
+ tools: [{ id: 't', label: 'T', gates: ['boom:bar'] }],
237
+ context: {},
238
+ evaluators: {
239
+ boom: async () => {
240
+ throw new Error('evaluator exploded');
241
+ },
242
+ },
243
+ })).rejects.toThrow('evaluator exploded');
244
+ });
245
+ it('respects falsy results from async evaluators (excludes the tool)', async () => {
246
+ const result = await composeDockAvailability({
247
+ tools: [{ id: 't', label: 'T', gates: ['x:y'] }],
248
+ context: {},
249
+ evaluators: { x: asyncFalse },
250
+ });
251
+ expect(result).toEqual([]);
252
+ });
253
+ // Regression: a gate prefix that names an inherited `Object.prototype`
254
+ // property (e.g. `constructor`, `toString`, `hasOwnProperty`, `valueOf`,
255
+ // `__proto__`) MUST NOT bypass the unknown-prefix fail-loud path. Prior
256
+ // to the fix, `evaluators[prefix]` resolved to a built-in function and
257
+ // got invoked, returning a truthy value and silently passing the gate.
258
+ it('throws on prototype-key gate prefixes (constructor, toString, hasOwnProperty, valueOf, __proto__)', async () => {
259
+ const evaluators = { permission: () => true };
260
+ for (const prefix of [
261
+ 'constructor',
262
+ 'toString',
263
+ 'hasOwnProperty',
264
+ 'valueOf',
265
+ '__proto__',
266
+ ]) {
267
+ await expect(composeDockAvailability({
268
+ tools: [{ id: 'x', label: 'X', gates: [`${prefix}:any`] }],
269
+ context: {},
270
+ evaluators,
271
+ })).rejects.toThrow(/No evaluator registered for gate prefix/);
272
+ }
273
+ });
274
+ it('throws when an evaluator entry is not a function', async () => {
275
+ await expect(composeDockAvailability({
276
+ tools: [{ id: 'x', label: 'X', gates: ['permission:any'] }],
277
+ context: {},
278
+ evaluators: {
279
+ // Intentional non-function evaluator — should fail loud.
280
+ permission: 'not-a-function',
281
+ },
282
+ })).rejects.toThrow(/No evaluator registered/);
283
+ });
284
+ // Regression for the TCtx generic parameterization (issue 1242 fix #5).
285
+ // Verifies the typed-context flow compiles end-to-end: the evaluator
286
+ // receives a typed `ctx` (string fields, not `unknown`) without a cast.
287
+ it('preserves the caller-supplied context type through to evaluators (TCtx generic)', async () => {
288
+ let observedUserId;
289
+ let observedTenantId;
290
+ const result = await composeDockAvailability({
291
+ tools: [{ id: 't', label: 'T', gates: ['permission:articles.publish'] }],
292
+ context: { userId: 'u-1', tenantId: 't-1' },
293
+ evaluators: {
294
+ permission: (gateId, ctx) => {
295
+ // No cast required — ctx.userId and ctx.tenantId are typed string.
296
+ observedUserId = ctx.userId;
297
+ observedTenantId = ctx.tenantId;
298
+ const [, slug] = gateId.split(':', 2);
299
+ return slug === 'articles.publish';
300
+ },
301
+ },
302
+ });
303
+ expect(result).toHaveLength(1);
304
+ expect(observedUserId).toBe('u-1');
305
+ expect(observedTenantId).toBe('t-1');
306
+ });
307
+ // Regression: an interface-style context (no string index signature) must
308
+ // be accepted by `TCtx`. The round-1 fixup parameterized
309
+ // `TCtx extends Record<string, unknown>`, which rejected interfaces under
310
+ // strict TS — the same trap we hit with `TActions` in #1239. The
311
+ // self-mapped constraint `{ [K in keyof TCtx]: unknown }` accepts
312
+ // interfaces without forcing the consumer to add an index signature.
313
+ //
314
+ // The compile-time guard lives in
315
+ // `./__tests__/typed-context-fixture/typed-context.ts` — see the JSDoc
316
+ // there. The runtime check below confirms the same interface-style
317
+ // context round-trips through evaluators at runtime.
318
+ it('accepts an interface-style TCtx (no string index signature)', async () => {
319
+ let observedUserId;
320
+ const result = await composeDockAvailability({
321
+ tools: [{ id: 't', label: 'T', gates: ['permission:any'] }],
322
+ context: { userId: 'u-1', tenantId: 't-1' },
323
+ evaluators: {
324
+ permission: (_gateId, ctx) => {
325
+ // No cast — ctx.userId is typed string.
326
+ observedUserId = ctx.userId;
327
+ return true;
328
+ },
329
+ },
330
+ });
331
+ expect(result).toHaveLength(1);
332
+ expect(observedUserId).toBe('u-1');
333
+ });
334
+ // Regression for fix #2 of round-3: `.every(Boolean)` fails OPEN for
335
+ // truthy non-booleans. `Boolean('false')`, `Boolean({})`, `Boolean([])`
336
+ // are all true, so an untyped evaluator returning a wrapped object, a
337
+ // sentinel string, or a number would silently grant access. The composer
338
+ // now uses strict `=== true`.
339
+ it('fails closed on truthy non-boolean evaluator returns', async () => {
340
+ // Evaluators MUST return boolean per the type, but consumers in plain
341
+ // JS or with untyped wrappers can slip non-boolean returns through.
342
+ // Verify that truthy non-booleans don't grant access.
343
+ const cases = [
344
+ {
345
+ id: 'string-true',
346
+ evaluator: () => 'true',
347
+ },
348
+ {
349
+ id: 'object',
350
+ evaluator: () => ({ allowed: false }),
351
+ },
352
+ {
353
+ id: 'array',
354
+ evaluator: () => [],
355
+ },
356
+ {
357
+ id: 'number-1',
358
+ evaluator: () => 1,
359
+ },
360
+ {
361
+ id: 'falsestring',
362
+ evaluator: () => 'false',
363
+ },
364
+ ];
365
+ for (const { id, evaluator } of cases) {
366
+ const result = await composeDockAvailability({
367
+ tools: [{ id, label: id, gates: ['permission:any'] }],
368
+ context: {},
369
+ evaluators: { permission: evaluator },
370
+ });
371
+ // fail-closed: gate doesn't pass
372
+ expect(result).toEqual([]);
373
+ }
374
+ });
375
+ it('passes only on literal `true` (not truthy values)', async () => {
376
+ const result = await composeDockAvailability({
377
+ tools: [{ id: 'pass-true', label: 'Pass', gates: ['permission:any'] }],
378
+ context: {},
379
+ evaluators: { permission: () => true },
380
+ });
381
+ expect(result).toEqual([{ id: 'pass-true', label: 'Pass' }]);
382
+ });
383
+ });
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Compile-time regression fixture for the `TCtx` generic on
3
+ * `composeDockAvailability` / `ComposeDockAvailabilityOptions` /
4
+ * `GateEvaluator`.
5
+ *
6
+ * This is the contract round-3 of PR #1242 is restoring:
7
+ *
8
+ * - `TCtx` must accept an INTERFACE (no string index signature). The
9
+ * round-1 fixup tightened the constraint to
10
+ * `TCtx extends Record<string, unknown>`, which silently rejected
11
+ * interface-style contexts — the same trap Copilot caught with
12
+ * `TActions` in PR #1239. The constraint is now a self-mapped
13
+ * `{ [K in keyof TCtx]: unknown }` (matching the `TActions` pattern in
14
+ * `../../types.ts`).
15
+ *
16
+ * - The default `TCtx = GateEvaluationContext` must keep existing
17
+ * untyped call sites compiling unchanged.
18
+ *
19
+ * - The factory's `<TCtx>` generic must flow through to each evaluator
20
+ * so `ctx.fieldName` is typed without a cast at the evaluator call
21
+ * site.
22
+ *
23
+ * Lives in a `.ts` file (NOT `.test.ts`) so:
24
+ * - `tsc --noEmit` (the package's `typecheck` script, run in CI via
25
+ * `pnpm turbo run typecheck`) does include it — the package's
26
+ * `tsconfig.svelte.json` includes `src/** /*.ts` and excludes only
27
+ * `**\/*.test.ts` and `**\/*.spec.ts`.
28
+ * - Vitest does NOT execute it (no `.test.ts` suffix), so the
29
+ * `_assertInterfaceTCtx*` symbols below never run — their bodies must
30
+ * just compile.
31
+ *
32
+ * Mirrors the same pattern as
33
+ * `../../__tests__/typed-tool-fixture/register-typed-tool.ts` (PR #1239).
34
+ */
35
+ import type { ComposeDockAvailabilityOptions, GateEvaluator } from '../types.js';
36
+ /**
37
+ * Interface-style context — no string index signature. Under a bare
38
+ * `Record<string, unknown>` constraint this fails to satisfy `TCtx`
39
+ * (TS2344). Under the self-mapped `{ [K in keyof TCtx]: unknown }`
40
+ * constraint it's accepted.
41
+ */
42
+ interface MyInterfaceContext {
43
+ userId: string;
44
+ tenantId: string;
45
+ }
46
+ /**
47
+ * Type-only assertion: an `Options` literal parameterized over an
48
+ * interface-style context must compile, and the evaluator must receive a
49
+ * typed `ctx` (no cast) with the consumer's field types.
50
+ *
51
+ * If `TCtx` ever tightens back to `Record<string, unknown>`, this
52
+ * declaration fails with TS2344 ("Type 'MyInterfaceContext' does not
53
+ * satisfy the constraint 'Record<string, unknown>'").
54
+ */
55
+ export declare const _assertInterfaceTCtxOptions: ComposeDockAvailabilityOptions<MyInterfaceContext>;
56
+ /**
57
+ * Type-only assertion: `GateEvaluator<MyInterfaceContext>` accepts an
58
+ * interface. Same regression as above, but exercised through the
59
+ * `GateEvaluator` alias directly (which `ComposeDockAvailabilityOptions`
60
+ * indexes into via `evaluators`).
61
+ */
62
+ export declare const _assertInterfaceTCtxEvaluator: GateEvaluator<MyInterfaceContext>;
63
+ /**
64
+ * Type-only assertion: the `composeDockAvailability<TCtx>` factory
65
+ * accepts an interface-style `TCtx` and threads it through to evaluators
66
+ * without erasure. Never called at runtime — its body just has to
67
+ * compile.
68
+ */
69
+ export declare function _assertInterfaceTCtxFactoryFlow(): Promise<void>;
70
+ /**
71
+ * Type-only assertion: the untyped (back-compat) call site must still
72
+ * compile with no generic argument and resolve `TCtx` to the default
73
+ * `GateEvaluationContext` (`Record<string, unknown>`). If the default
74
+ * ever drifted, every existing untyped consumer would break.
75
+ */
76
+ export declare function _assertUntypedDefaultTCtx(): Promise<void>;
77
+ export {};
78
+ //# sourceMappingURL=typed-context-fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-context-fixture.d.ts","sourceRoot":"","sources":["../../../../../src/components/workspace/server/__tests__/typed-context-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,KAAK,EACV,8BAA8B,EAG9B,aAAa,EACd,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,EAAE,8BAA8B,CAAC,kBAAkB,CAYxF,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,EAAE,aAAa,CACvD,kBAAkB,CAInB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,+BAA+B,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBrE;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAO/D"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Compile-time regression fixture for the `TCtx` generic on
3
+ * `composeDockAvailability` / `ComposeDockAvailabilityOptions` /
4
+ * `GateEvaluator`.
5
+ *
6
+ * This is the contract round-3 of PR #1242 is restoring:
7
+ *
8
+ * - `TCtx` must accept an INTERFACE (no string index signature). The
9
+ * round-1 fixup tightened the constraint to
10
+ * `TCtx extends Record<string, unknown>`, which silently rejected
11
+ * interface-style contexts — the same trap Copilot caught with
12
+ * `TActions` in PR #1239. The constraint is now a self-mapped
13
+ * `{ [K in keyof TCtx]: unknown }` (matching the `TActions` pattern in
14
+ * `../../types.ts`).
15
+ *
16
+ * - The default `TCtx = GateEvaluationContext` must keep existing
17
+ * untyped call sites compiling unchanged.
18
+ *
19
+ * - The factory's `<TCtx>` generic must flow through to each evaluator
20
+ * so `ctx.fieldName` is typed without a cast at the evaluator call
21
+ * site.
22
+ *
23
+ * Lives in a `.ts` file (NOT `.test.ts`) so:
24
+ * - `tsc --noEmit` (the package's `typecheck` script, run in CI via
25
+ * `pnpm turbo run typecheck`) does include it — the package's
26
+ * `tsconfig.svelte.json` includes `src/** /*.ts` and excludes only
27
+ * `**\/*.test.ts` and `**\/*.spec.ts`.
28
+ * - Vitest does NOT execute it (no `.test.ts` suffix), so the
29
+ * `_assertInterfaceTCtx*` symbols below never run — their bodies must
30
+ * just compile.
31
+ *
32
+ * Mirrors the same pattern as
33
+ * `../../__tests__/typed-tool-fixture/register-typed-tool.ts` (PR #1239).
34
+ */
35
+ import { composeDockAvailability } from '../compose-availability.js';
36
+ /**
37
+ * Type-only assertion: an `Options` literal parameterized over an
38
+ * interface-style context must compile, and the evaluator must receive a
39
+ * typed `ctx` (no cast) with the consumer's field types.
40
+ *
41
+ * If `TCtx` ever tightens back to `Record<string, unknown>`, this
42
+ * declaration fails with TS2344 ("Type 'MyInterfaceContext' does not
43
+ * satisfy the constraint 'Record<string, unknown>'").
44
+ */
45
+ export const _assertInterfaceTCtxOptions = {
46
+ tools: [],
47
+ context: { userId: 'u-1', tenantId: 't-1' },
48
+ evaluators: {
49
+ permission: (gateId, ctx) => {
50
+ // No cast required — ctx.userId / ctx.tenantId are typed `string`.
51
+ const _userId = ctx.userId;
52
+ const _tenantId = ctx.tenantId;
53
+ return gateId.startsWith('permission:');
54
+ },
55
+ },
56
+ };
57
+ /**
58
+ * Type-only assertion: `GateEvaluator<MyInterfaceContext>` accepts an
59
+ * interface. Same regression as above, but exercised through the
60
+ * `GateEvaluator` alias directly (which `ComposeDockAvailabilityOptions`
61
+ * indexes into via `evaluators`).
62
+ */
63
+ export const _assertInterfaceTCtxEvaluator = (gateId, ctx) => {
64
+ const _ = ctx.userId;
65
+ return gateId === 'permission:any';
66
+ };
67
+ /**
68
+ * Type-only assertion: the `composeDockAvailability<TCtx>` factory
69
+ * accepts an interface-style `TCtx` and threads it through to evaluators
70
+ * without erasure. Never called at runtime — its body just has to
71
+ * compile.
72
+ */
73
+ export async function _assertInterfaceTCtxFactoryFlow() {
74
+ const tools = [
75
+ { id: 't', label: 'T', gates: ['permission:any'] },
76
+ ];
77
+ await composeDockAvailability({
78
+ tools,
79
+ context: { userId: 'u-1', tenantId: 't-1' },
80
+ evaluators: {
81
+ permission: (_gateId, ctx) => {
82
+ // TYPED: ctx.userId is `string`, not `unknown`. If the factory
83
+ // dropped its generic on the evaluator signature, the next line
84
+ // would only compile as `unknown`.
85
+ const _userId = ctx.userId;
86
+ return true;
87
+ },
88
+ },
89
+ });
90
+ }
91
+ /**
92
+ * Type-only assertion: the untyped (back-compat) call site must still
93
+ * compile with no generic argument and resolve `TCtx` to the default
94
+ * `GateEvaluationContext` (`Record<string, unknown>`). If the default
95
+ * ever drifted, every existing untyped consumer would break.
96
+ */
97
+ export async function _assertUntypedDefaultTCtx() {
98
+ const ctx = { foo: 'bar' };
99
+ await composeDockAvailability({
100
+ tools: [{ id: 't', label: 'T' }],
101
+ context: ctx,
102
+ evaluators: {},
103
+ });
104
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Server-side dock availability gate composer.
3
+ *
4
+ * Consumer's `fetchAvailability` endpoint calls `composeDockAvailability`
5
+ * with the registered tools, a caller-supplied context, and a map of
6
+ * gate evaluators (typically wrapping `PermissionResolver` from
7
+ * smrt-users and `FeatureResolver` from smrt-features). It returns the
8
+ * filtered `AvailableTool[]` the dock's client-side `fetchAvailability`
9
+ * resolves to.
10
+ *
11
+ * Server-side by design: no Svelte / DOM imports, no client-only state.
12
+ * See happyvertical/smrt#1226 (Phase 4c) and #1235 for the registry
13
+ * audit that motivated this server-first pattern.
14
+ */
15
+ import type { AvailableTool } from '../types.js';
16
+ import type { ComposeDockAvailabilityOptions, GateEvaluationContext } from './types.js';
17
+ /**
18
+ * Compose the `availableTools` list for a tools dock by evaluating each
19
+ * tool's `gates` against the provided evaluators. Tools where ALL gates
20
+ * resolve to `true` are included (AND semantics).
21
+ *
22
+ * Tools without `gates` (or with an empty `gates` array) are
23
+ * unconditionally included — gating is opt-in, existing tool definitions
24
+ * keep working.
25
+ *
26
+ * Throws if a gate's prefix doesn't match any registered evaluator —
27
+ * misconfiguration should fail loudly, not silently leak tools to users
28
+ * who shouldn't see them.
29
+ *
30
+ * Gate evaluation is parallel within a tool and across tools (`Promise.all`
31
+ * fan-out), so a slow evaluator on one gate doesn't block unrelated tools.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import {
36
+ * composeDockAvailability,
37
+ * type GateEvaluationContext,
38
+ * } from '@happyvertical/smrt-svelte/workspace/server';
39
+ * import { PermissionResolver } from '@happyvertical/smrt-users';
40
+ * import { FeatureResolver } from '@happyvertical/smrt-features';
41
+ *
42
+ * // Caller narrows the context shape so evaluators get typed access
43
+ * // without casts:
44
+ * interface MyContext extends GateEvaluationContext {
45
+ * userId: string;
46
+ * tenantId: string;
47
+ * }
48
+ *
49
+ * const available = await composeDockAvailability<MyContext>({
50
+ * tools: [
51
+ * { id: 'governance', label: 'Claim Audit', gates: ['permission:content.governance.view'] },
52
+ * { id: 'video-gen', label: 'Video', gates: ['feature:video-tools'] },
53
+ * { id: 'chat', label: 'Chat' }, // no gates → always visible
54
+ * ],
55
+ * context: { userId: 'user-1', tenantId: 'tenant-1' },
56
+ * evaluators: {
57
+ * permission: async (gateId, ctx) => {
58
+ * const [, slug] = gateId.split(':', 2);
59
+ * return permissionResolver.hasPermission(ctx.userId, ctx.tenantId, slug);
60
+ * },
61
+ * feature: async (gateId, ctx) => {
62
+ * const [, key] = gateId.split(':', 2);
63
+ * return featureResolver.isEnabled(key, { tenantId: ctx.tenantId });
64
+ * },
65
+ * },
66
+ * });
67
+ * // → AvailableTool[] filtered by gates
68
+ * ```
69
+ */
70
+ export declare function composeDockAvailability<TCtx extends {
71
+ [K in keyof TCtx]: unknown;
72
+ } = GateEvaluationContext>(options: ComposeDockAvailabilityOptions<TCtx>): Promise<AvailableTool[]>;
73
+ //# sourceMappingURL=compose-availability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-availability.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/server/compose-availability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EACV,8BAA8B,EAC9B,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,SAAS;KAAG,CAAC,IAAI,MAAM,IAAI,GAAG,OAAO;CAAE,GAAG,qBAAqB,EACnE,OAAO,EAAE,8BAA8B,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAuDzE"}