akanjs 3.0.0-alpha.2 → 3.0.0-alpha.21

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 (388) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/base/symbols.ts +4 -0
  4. package/client/clientRuntime.ts +8 -0
  5. package/client/cn.ts +7 -0
  6. package/client/csrTypes.ts +2 -0
  7. package/client/frameDebug.ts +3 -2
  8. package/common/Logger.ts +4 -0
  9. package/common/deepObjectify.ts +21 -7
  10. package/common/index.ts +14 -0
  11. package/common/mcpExposure.ts +99 -0
  12. package/common/pathSet.ts +17 -5
  13. package/common/routeConvention.ts +30 -0
  14. package/constant/crystalize.ts +3 -1
  15. package/constant/fieldInfo.ts +6 -0
  16. package/constant/getDefault.ts +37 -9
  17. package/constant/immerify.ts +1 -1
  18. package/constant/index.ts +2 -0
  19. package/constant/labelOf.ts +17 -0
  20. package/constant/mask.ts +60 -0
  21. package/constant/purify.ts +17 -11
  22. package/constant/types.ts +14 -12
  23. package/dictionary/DictionaryLookup.ts +30 -0
  24. package/dictionary/agent.dictionary.ts +31 -0
  25. package/dictionary/agentTurn.dictionary.ts +29 -0
  26. package/dictionary/base.dictionary.ts +8 -0
  27. package/dictionary/dictInfo.ts +8 -0
  28. package/dictionary/dictionary.ts +9 -3
  29. package/dictionary/index.ts +1 -0
  30. package/document/database.ts +21 -0
  31. package/document/filterMeta.ts +7 -0
  32. package/document/index.ts +1 -0
  33. package/document/into.ts +7 -1
  34. package/document/noDocumentError.ts +12 -0
  35. package/fetch/agentTurn.ts +19 -0
  36. package/fetch/client/fetchClient.ts +71 -13
  37. package/fetch/client/wsClient.ts +17 -2
  38. package/fetch/fetchType/endpointFetch.type.ts +10 -4
  39. package/fetch/index.ts +1 -0
  40. package/local/apps/serverLifecycle/serverLifecycle-local.db +0 -0
  41. package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
  42. package/local/apps/serverLifecycle/serverLifecycle-local.db-wal +0 -0
  43. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db +0 -0
  44. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
  45. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-wal +0 -0
  46. package/package.json +11 -9
  47. package/server/akanApp.ts +30 -34
  48. package/server/akanOption.ts +65 -7
  49. package/server/akanServer.ts +172 -7
  50. package/server/animatedImage.ts +83 -0
  51. package/server/artifact/routeClientCache.ts +14 -0
  52. package/server/assetEncoding.ts +47 -0
  53. package/server/devtools/signalSerializer.ts +2 -2
  54. package/server/devtools/types.ts +2 -2
  55. package/server/di/diLifecycle.ts +31 -3
  56. package/server/di/predefinedAdaptor.ts +6 -0
  57. package/server/imageOptimizer.ts +33 -46
  58. package/server/index.ts +1 -2
  59. package/server/mcp/McpAuth.ts +177 -0
  60. package/server/mcp/McpDispatcher.ts +245 -0
  61. package/server/mcp/McpEventStream.ts +76 -0
  62. package/server/mcp/McpExecutionContext.ts +105 -0
  63. package/server/mcp/McpRouter.ts +591 -0
  64. package/server/mcp/index.ts +5 -0
  65. package/server/resolver/CascadeRunner.ts +1 -1
  66. package/server/resolver/database.resolver.ts +42 -5
  67. package/server/resolver/service.resolver.ts +29 -0
  68. package/server/resolver/signal.resolver.ts +16 -1
  69. package/server/routeTreeBuilder.ts +2 -44
  70. package/server/rscWorker.tsx +6 -2
  71. package/server/subRouteIndexDocument.tsx +61 -0
  72. package/server/systemPageDocument.tsx +2 -2
  73. package/server/systemPages.tsx +49 -16
  74. package/server/vendor/akanjs-fetch.ts +1 -0
  75. package/server/webRouter.ts +159 -35
  76. package/service/agent.service.ts +14 -0
  77. package/service/base.service.ts +2 -1
  78. package/service/index.ts +1 -0
  79. package/service/predefinedAdaptor/database.adaptor.ts +78 -24
  80. package/service/predefinedAdaptor/deepseekLlm.ts +230 -0
  81. package/service/predefinedAdaptor/index.ts +3 -0
  82. package/service/predefinedAdaptor/insightQuery.ts +183 -0
  83. package/service/predefinedAdaptor/llm.adaptor.ts +76 -0
  84. package/service/predefinedAdaptor/role.adaptor.ts +2 -0
  85. package/service/predefinedAdaptor/schedule.adaptor.ts +12 -5
  86. package/service/serviceModule.ts +17 -0
  87. package/service/types.ts +4 -0
  88. package/signal/agent/AgentCatalogue.ts +165 -0
  89. package/signal/agent/index.ts +1 -0
  90. package/signal/agent.signal.ts +42 -0
  91. package/signal/agentTurn.ts +8 -0
  92. package/signal/agentTurnStream.ts +48 -0
  93. package/signal/base.signal.ts +2 -1
  94. package/signal/endpointInfo.ts +38 -2
  95. package/signal/guard.ts +13 -1
  96. package/signal/guards.ts +52 -1
  97. package/signal/index.ts +6 -0
  98. package/signal/mcp/McpDocument.ts +286 -0
  99. package/signal/mcp/McpProgress.ts +106 -0
  100. package/signal/mcp/McpUriTemplate.ts +85 -0
  101. package/signal/mcp/Msg.ts +368 -0
  102. package/signal/mcp/index.ts +5 -0
  103. package/signal/mcp/mcpProtocol.ts +120 -0
  104. package/signal/middleware.ts +7 -3
  105. package/signal/openapi/openapi.ts +32 -171
  106. package/signal/schema/JsonSchemaBuilder.ts +211 -0
  107. package/signal/schema/index.ts +1 -0
  108. package/signal/signalContext.ts +85 -9
  109. package/signal/slice.ts +9 -9
  110. package/signal/types.ts +1 -1
  111. package/store/action.ts +11 -22
  112. package/store/actionTag.ts +33 -0
  113. package/store/agent/AgentBridge.ts +323 -0
  114. package/store/agent/AgentContext.ts +74 -0
  115. package/store/agent/AgentPrompts.ts +82 -0
  116. package/store/agent/AgentVisibility.ts +68 -0
  117. package/store/agent/ScreenReader.ts +208 -0
  118. package/store/agent/StoreCatalogue.ts +351 -0
  119. package/store/agent/StoreSurfaceSource.ts +122 -0
  120. package/store/agent/index.ts +9 -0
  121. package/store/agent/storeSurface.ts +28 -0
  122. package/store/agent/types.ts +50 -0
  123. package/store/agentic/StToolBuilder.ts +199 -0
  124. package/store/agentic/attachAgentic.ts +22 -0
  125. package/store/agentic/index.ts +5 -0
  126. package/store/agentic/readableValue.ts +17 -0
  127. package/store/agentic/useStExpose.ts +18 -0
  128. package/store/agentic/useStState.ts +35 -0
  129. package/store/baseSt.ts +7 -0
  130. package/store/databaseStateNames.ts +31 -0
  131. package/store/formSetterNames.ts +21 -0
  132. package/store/index.ts +8 -0
  133. package/store/rootStore.ts +3 -1
  134. package/store/sliceRole.ts +36 -0
  135. package/store/state.ts +2 -12
  136. package/store/store.ts +19 -1
  137. package/store/storeInstance.ts +165 -20
  138. package/store/storeRegistry.ts +16 -1
  139. package/store/types.ts +18 -0
  140. package/store/withSelector.ts +7 -8
  141. package/test/registerDom.ts +4 -0
  142. package/types/base/symbols.d.ts +4 -0
  143. package/types/client/cn.d.ts +5 -0
  144. package/types/client/csrTypes.d.ts +2 -0
  145. package/types/common/Logger.d.ts +2 -0
  146. package/types/common/deepObjectify.d.ts +4 -2
  147. package/types/common/index.d.ts +2 -1
  148. package/types/common/mcpExposure.d.ts +60 -0
  149. package/types/common/routeConvention.d.ts +8 -0
  150. package/types/constant/fieldInfo.d.ts +1 -0
  151. package/types/constant/getDefault.d.ts +5 -0
  152. package/types/constant/index.d.ts +2 -0
  153. package/types/constant/labelOf.d.ts +6 -0
  154. package/types/constant/mask.d.ts +34 -0
  155. package/types/constant/purify.d.ts +2 -2
  156. package/types/constant/types.d.ts +2 -2
  157. package/types/dictionary/DictionaryLookup.d.ts +14 -0
  158. package/types/dictionary/agent.dictionary.d.ts +1 -0
  159. package/types/dictionary/agentTurn.dictionary.d.ts +1 -0
  160. package/types/dictionary/base.dictionary.d.ts +1 -1
  161. package/types/dictionary/dictInfo.d.ts +6 -0
  162. package/types/dictionary/dictionary.d.ts +11 -9
  163. package/types/dictionary/index.d.ts +1 -0
  164. package/types/document/database.d.ts +20 -0
  165. package/types/document/filterMeta.d.ts +1 -0
  166. package/types/document/index.d.ts +1 -0
  167. package/types/document/into.d.ts +6 -1
  168. package/types/document/noDocumentError.d.ts +12 -0
  169. package/types/fetch/agentTurn.d.ts +593 -0
  170. package/types/fetch/client/fetchClient.d.ts +10 -0
  171. package/types/fetch/fetchType/endpointFetch.type.d.ts +5 -3
  172. package/types/fetch/index.d.ts +1 -0
  173. package/types/server/akanOption.d.ts +35 -7
  174. package/types/server/akanServer.d.ts +44 -1
  175. package/types/server/animatedImage.d.ts +7 -0
  176. package/types/server/artifact/routeClientCache.d.ts +6 -0
  177. package/types/server/assetEncoding.d.ts +7 -0
  178. package/types/server/devtools/types.d.ts +2 -2
  179. package/types/server/di/predefinedAdaptor.d.ts +4 -1
  180. package/types/server/index.d.ts +0 -2
  181. package/types/server/mcp/McpAuth.d.ts +62 -0
  182. package/types/server/mcp/McpDispatcher.d.ts +54 -0
  183. package/types/server/mcp/McpEventStream.d.ts +18 -0
  184. package/types/server/mcp/McpExecutionContext.d.ts +44 -0
  185. package/types/server/mcp/McpRouter.d.ts +60 -0
  186. package/types/server/mcp/index.d.ts +5 -0
  187. package/types/server/mcp.d.ts +1 -0
  188. package/types/server/subRouteIndexDocument.d.ts +8 -0
  189. package/types/server/systemPageDocument.d.ts +1 -0
  190. package/types/server/systemPages.d.ts +5 -0
  191. package/types/server/vendor/akanjs-fetch.d.ts +1 -0
  192. package/types/service/agent.service.d.ts +12 -0
  193. package/types/service/base.service.d.ts +4 -0
  194. package/types/service/index.d.ts +1 -0
  195. package/types/service/predefinedAdaptor/database.adaptor.d.ts +24 -2
  196. package/types/service/predefinedAdaptor/deepseekLlm.d.ts +64 -0
  197. package/types/service/predefinedAdaptor/index.d.ts +3 -0
  198. package/types/service/predefinedAdaptor/insightQuery.d.ts +50 -0
  199. package/types/service/predefinedAdaptor/llm.adaptor.d.ts +68 -0
  200. package/types/service/predefinedAdaptor/role.adaptor.d.ts +2 -0
  201. package/types/service/predefinedAdaptor/schedule.adaptor.d.ts +10 -6
  202. package/types/service/types.d.ts +4 -1
  203. package/types/signal/agent/AgentCatalogue.d.ts +100 -0
  204. package/types/signal/agent/index.d.ts +1 -0
  205. package/types/signal/agent.d.ts +1 -0
  206. package/types/signal/agent.signal.d.ts +29 -0
  207. package/types/signal/agentTurn.d.ts +9 -0
  208. package/types/signal/agentTurnStream.d.ts +16 -0
  209. package/types/signal/base.signal.d.ts +1 -1
  210. package/types/signal/endpointInfo.d.ts +21 -3
  211. package/types/signal/guard.d.ts +11 -0
  212. package/types/signal/guards.d.ts +22 -1
  213. package/types/signal/index.d.ts +6 -0
  214. package/types/signal/mcp/McpDocument.d.ts +65 -0
  215. package/types/signal/mcp/McpProgress.d.ts +40 -0
  216. package/types/signal/mcp/McpUriTemplate.d.ts +26 -0
  217. package/types/signal/mcp/Msg.d.ts +143 -0
  218. package/types/signal/mcp/index.d.ts +5 -0
  219. package/types/signal/mcp/mcpProtocol.d.ts +107 -0
  220. package/types/signal/mcp.d.ts +1 -0
  221. package/types/signal/openapi/openapi.d.ts +3 -3
  222. package/types/signal/schema/JsonSchemaBuilder.d.ts +47 -0
  223. package/types/signal/schema/index.d.ts +1 -0
  224. package/types/signal/schema.d.ts +1 -0
  225. package/types/signal/signalContext.d.ts +16 -1
  226. package/types/signal/slice.d.ts +8 -8
  227. package/types/signal/types.d.ts +1 -1
  228. package/types/store/actionTag.d.ts +21 -0
  229. package/types/store/agent/AgentBridge.d.ts +77 -0
  230. package/types/store/agent/AgentContext.d.ts +16 -0
  231. package/types/store/agent/AgentPrompts.d.ts +31 -0
  232. package/types/store/agent/AgentVisibility.d.ts +21 -0
  233. package/types/store/agent/ScreenReader.d.ts +11 -0
  234. package/types/store/agent/StoreCatalogue.d.ts +26 -0
  235. package/types/store/agent/StoreSurfaceSource.d.ts +18 -0
  236. package/types/store/agent/index.d.ts +9 -0
  237. package/types/store/agent/storeSurface.d.ts +14 -0
  238. package/types/store/agent/types.d.ts +49 -0
  239. package/types/store/agent.d.ts +1 -0
  240. package/types/store/agentic/StToolBuilder.d.ts +41 -0
  241. package/types/store/agentic/attachAgentic.d.ts +14 -0
  242. package/types/store/agentic/index.d.ts +5 -0
  243. package/types/store/agentic/readableValue.d.ts +3 -0
  244. package/types/store/agentic/useStExpose.d.ts +8 -0
  245. package/types/store/agentic/useStState.d.ts +12 -0
  246. package/types/store/agentic.d.ts +1 -0
  247. package/types/store/baseSt.d.ts +29 -22
  248. package/types/store/databaseStateNames.d.ts +25 -0
  249. package/types/store/formSetterNames.d.ts +16 -0
  250. package/types/store/index.d.ts +7 -0
  251. package/types/store/rootStore.d.ts +5 -1
  252. package/types/store/sliceRole.d.ts +25 -0
  253. package/types/store/store.d.ts +7 -2
  254. package/types/store/storeInstance.d.ts +33 -1
  255. package/types/store/storeRegistry.d.ts +5 -0
  256. package/types/store/types.d.ts +15 -0
  257. package/types/store/withSelector.d.ts +7 -8
  258. package/types/test/registerDom.d.ts +1 -0
  259. package/types/ui/Agent/Approval.d.ts +7 -0
  260. package/types/ui/Agent/Bubble.d.ts +13 -0
  261. package/types/ui/Agent/Chat.d.ts +24 -0
  262. package/types/ui/Agent/Context.d.ts +9 -0
  263. package/types/ui/Agent/Dock.d.ts +16 -0
  264. package/types/ui/Agent/Guide.d.ts +9 -0
  265. package/types/ui/Agent/Section.d.ts +10 -0
  266. package/types/ui/Agent/StateKey.d.ts +16 -0
  267. package/types/ui/Agent/Tool.d.ts +15 -0
  268. package/types/ui/Agent/Transcript.d.ts +13 -0
  269. package/types/ui/Agent/Zone.d.ts +23 -0
  270. package/types/ui/Agent/fetchRunner.d.ts +12 -0
  271. package/types/ui/Agent/index.d.ts +17 -0
  272. package/types/ui/Agent/index_.d.ts +1 -0
  273. package/types/ui/Agent/sessionHistory.d.ts +12 -0
  274. package/types/ui/Agent.d.ts +1 -0
  275. package/types/ui/Badge.d.ts +1 -1
  276. package/types/ui/Button.d.ts +1 -1
  277. package/types/ui/CsrImage.d.ts +1 -1
  278. package/types/ui/Dropdown.d.ts +2 -0
  279. package/types/ui/Image.d.ts +3 -3
  280. package/types/ui/Layout/BottomInset.d.ts +2 -1
  281. package/types/ui/Layout/index.d.ts +1 -1
  282. package/types/ui/Signal/style.d.ts +4 -1
  283. package/types/ui/UiOverride/context.d.ts +14 -2
  284. package/types/ui/agentAttrs.d.ts +14 -0
  285. package/types/ui/index.d.ts +4 -1
  286. package/types/ui/overlayLayer.d.ts +24 -0
  287. package/types/ui/recipe/badgeRecipe.d.ts +7 -3
  288. package/types/ui/recipe/buttonRecipe.d.ts +7 -3
  289. package/types/ui/recipe/inputRecipe.d.ts +5 -1
  290. package/types/vendor/use-agentic/AgentProvider.d.ts +18 -0
  291. package/types/vendor/use-agentic/AgentScope.d.ts +9 -0
  292. package/types/vendor/use-agentic/AgentSession.d.ts +50 -0
  293. package/types/vendor/use-agentic/Agentic.d.ts +21 -0
  294. package/types/vendor/use-agentic/AgenticSurface.d.ts +44 -0
  295. package/types/vendor/use-agentic/httpRunner.d.ts +15 -0
  296. package/types/vendor/use-agentic/index.d.ts +13 -0
  297. package/types/vendor/use-agentic/surfaceContext.d.ts +5 -0
  298. package/types/vendor/use-agentic/types.d.ts +133 -0
  299. package/types/vendor/use-agentic/useAgent.d.ts +4 -0
  300. package/types/vendor/use-agentic/useAgentGuide.d.ts +6 -0
  301. package/types/vendor/use-agentic/useAgentResource.d.ts +7 -0
  302. package/types/vendor/use-agentic/useAgentState.d.ts +13 -0
  303. package/types/vendor/use-agentic/useAgentTool.d.ts +16 -0
  304. package/types/vendor/use-agentic.d.ts +1 -0
  305. package/types/webkit/index.d.ts +3 -0
  306. package/types/webkit/lazy.d.ts +12 -0
  307. package/types/webkit/useCsrValues.d.ts +3 -3
  308. package/types/webkit/useEscapeKey.d.ts +5 -0
  309. package/types/webkit/useFrameRuntime.d.ts +6 -1
  310. package/types/webkit/useScreenScope.d.ts +18 -0
  311. package/ui/Agent/Approval.tsx +29 -0
  312. package/ui/Agent/Bubble.tsx +74 -0
  313. package/ui/Agent/Chat.tsx +225 -0
  314. package/ui/Agent/Context.tsx +38 -0
  315. package/ui/Agent/Dock.tsx +72 -0
  316. package/ui/Agent/Guide.tsx +16 -0
  317. package/ui/Agent/Section.tsx +24 -0
  318. package/ui/Agent/StateKey.tsx +44 -0
  319. package/ui/Agent/Tool.tsx +66 -0
  320. package/ui/Agent/Transcript.tsx +33 -0
  321. package/ui/Agent/Zone.tsx +48 -0
  322. package/ui/Agent/fetchRunner.ts +30 -0
  323. package/ui/Agent/index.ts +12 -0
  324. package/ui/Agent/index_.tsx +4 -0
  325. package/ui/Agent/sessionHistory.ts +33 -0
  326. package/ui/Badge.tsx +3 -3
  327. package/ui/BottomSheet.tsx +5 -0
  328. package/ui/Button.tsx +6 -2
  329. package/ui/Constant/Doc.tsx +1 -1
  330. package/ui/CsrImage.tsx +1 -1
  331. package/ui/Data/ListContainer.tsx +1 -1
  332. package/ui/DatePicker.tsx +5 -4
  333. package/ui/Dialog/Modal.tsx +12 -15
  334. package/ui/DraggableList.tsx +3 -1
  335. package/ui/Dropdown.tsx +33 -11
  336. package/ui/Field.tsx +30 -16
  337. package/ui/Image.tsx +3 -3
  338. package/ui/Input.tsx +14 -5
  339. package/ui/Layout/BottomInset.tsx +6 -1
  340. package/ui/Load/Units.tsx +11 -2
  341. package/ui/Load/View.tsx +7 -2
  342. package/ui/Loading/ProgressBar.tsx +8 -1
  343. package/ui/Menu.tsx +7 -8
  344. package/ui/Model/EditModal.tsx +37 -2
  345. package/ui/Model/SureToRemove.tsx +2 -1
  346. package/ui/Model/index_.tsx +42 -15
  347. package/ui/ObjectId.tsx +3 -4
  348. package/ui/Pagination.tsx +3 -4
  349. package/ui/Popconfirm.tsx +8 -7
  350. package/ui/Select.tsx +6 -4
  351. package/ui/Signal/RestApi.tsx +43 -16
  352. package/ui/Signal/WebSocket.tsx +1 -1
  353. package/ui/Signal/style.ts +6 -1
  354. package/ui/Switch.tsx +2 -0
  355. package/ui/System/CSR.tsx +6 -2
  356. package/ui/System/ThemeToggle.tsx +55 -33
  357. package/ui/ToggleSelect.tsx +4 -3
  358. package/ui/Tooltip.tsx +2 -1
  359. package/ui/UiOverride/context.ts +14 -2
  360. package/ui/agentAttrs.ts +19 -0
  361. package/ui/index.ts +10 -1
  362. package/ui/overlayLayer.ts +39 -0
  363. package/ui/recipe/badgeRecipe.ts +22 -3
  364. package/ui/recipe/buttonRecipe.ts +51 -2
  365. package/ui/recipe/factory.ts +2 -2
  366. package/ui/recipe/inputRecipe.ts +18 -4
  367. package/vendor/use-agentic/AgentProvider.tsx +39 -0
  368. package/vendor/use-agentic/AgentScope.tsx +20 -0
  369. package/vendor/use-agentic/AgentSession.ts +292 -0
  370. package/vendor/use-agentic/Agentic.tsx +44 -0
  371. package/vendor/use-agentic/AgenticSurface.ts +294 -0
  372. package/vendor/use-agentic/WIRE.md +57 -0
  373. package/vendor/use-agentic/httpRunner.ts +115 -0
  374. package/vendor/use-agentic/index.ts +14 -0
  375. package/vendor/use-agentic/surfaceContext.ts +9 -0
  376. package/vendor/use-agentic/types.ts +144 -0
  377. package/vendor/use-agentic/useAgent.ts +17 -0
  378. package/vendor/use-agentic/useAgentGuide.ts +16 -0
  379. package/vendor/use-agentic/useAgentResource.ts +30 -0
  380. package/vendor/use-agentic/useAgentState.ts +61 -0
  381. package/vendor/use-agentic/useAgentTool.ts +55 -0
  382. package/webkit/bootCsr.tsx +2 -33
  383. package/webkit/index.ts +3 -0
  384. package/webkit/lazy.tsx +27 -3
  385. package/webkit/useCsrValues.ts +121 -4
  386. package/webkit/useEscapeKey.tsx +42 -0
  387. package/webkit/useFrameRuntime.ts +65 -32
  388. package/webkit/useScreenScope.tsx +49 -0
@@ -8,6 +8,7 @@ import { AiOutlineDelete } from "react-icons/ai";
8
8
 
9
9
  import { buttonRecipe } from "../Button";
10
10
  import { Modal } from "../Modal";
11
+ import { inputRecipe } from "../recipe";
11
12
 
12
13
  interface SureToRemoveProps {
13
14
  className?: string;
@@ -95,7 +96,7 @@ export default function SureToRemove({
95
96
  </div>
96
97
  {typeNameToRemove ? (
97
98
  <input
98
- className="input w-full text-center"
99
+ className={inputRecipe({}, "text-center")}
99
100
  placeholder={`${l(`${modelName}.modelName` as "base.new")} name`}
100
101
  value={repeatName}
101
102
  onChange={(e) => {
@@ -1,17 +1,44 @@
1
1
  import { lazy } from "akanjs/webkit";
2
2
 
3
- export const ViewModal = lazy(() => import("./ViewModal"));
4
- export const EditModal = lazy(() => import("./EditModal"));
5
- export const View = lazy(() => import("./View"));
6
- export const SureToRemove = lazy(() => import("./SureToRemove"));
7
- export const Remove = lazy(() => import("./Remove"));
8
- export const NewWrapper = lazy(() => import("./NewWrapper"));
9
- export const EditWrapper = lazy(() => import("./EditWrapper"));
10
- export const RemoveWrapper = lazy(() => import("./RemoveWrapper"));
11
- export const LoadInit = lazy(() => import("./LoadInit"));
12
- export const LoadView = lazy(() => import("./LoadView"));
13
- export const ViewWrapper = lazy(() => import("./ViewWrapper"));
14
- export const ViewEditModal = lazy(() => import("./ViewEditModal"));
15
- export const Edit = lazy(() => import("./Edit"));
16
- export const New = lazy(() => import("./New"));
17
- export const AdminPanel = lazy(() => import("./AdminPanel"));
3
+ /**
4
+ * Every Model export carries its own Suspense boundary.
5
+ *
6
+ * These mount on interaction — a modal body, a dropdown item, a confirm shell — long after the page is
7
+ * painted, and a chunk that resolves then would otherwise suspend all the way to the route and repaint
8
+ * the page as its loading fallback, once per fresh load.
9
+ */
10
+ const withSuspense = { suspense: true } as const;
11
+
12
+ /**
13
+ * A fallback here may only be a host element. This module has no `"use client"`, so a client component
14
+ * referenced from it `Loading.Skeleton` was the one tried — resolves to `undefined` inside the thunk
15
+ * and the render throws "Element type is invalid", taking the whole page segment under the layout with
16
+ * it. Marking the barrel `"use client"` is worse: `Model.*` becomes a real server→client boundary and
17
+ * apps passing crystalized model instances as props fail serialization at boot. Plain markup crosses
18
+ * neither line.
19
+ *
20
+ * Only the two exports that occupy space of their own get it. The triggers wrap the caller's own
21
+ * children, so a fixed block would put a slab where a small button belongs, and the modals render `null`
22
+ * until opened, so a block would appear where nothing ever shows. For those the collapse is a blink the
23
+ * size of a button; here it is the page body dropping to zero height and snapping back.
24
+ */
25
+ const bodyFallback = {
26
+ suspense: true,
27
+ loading: () => <div className="min-h-40 w-full animate-pulse rounded-md bg-muted" />,
28
+ } as const;
29
+
30
+ export const ViewModal = lazy(() => import("./ViewModal"), withSuspense);
31
+ export const EditModal = lazy(() => import("./EditModal"), withSuspense);
32
+ export const View = lazy(() => import("./View"), bodyFallback);
33
+ export const SureToRemove = lazy(() => import("./SureToRemove"), withSuspense);
34
+ export const Remove = lazy(() => import("./Remove"), withSuspense);
35
+ export const NewWrapper = lazy(() => import("./NewWrapper"), withSuspense);
36
+ export const EditWrapper = lazy(() => import("./EditWrapper"), withSuspense);
37
+ export const RemoveWrapper = lazy(() => import("./RemoveWrapper"), withSuspense);
38
+ export const LoadInit = lazy(() => import("./LoadInit"), withSuspense);
39
+ export const LoadView = lazy(() => import("./LoadView"), withSuspense);
40
+ export const ViewWrapper = lazy(() => import("./ViewWrapper"), withSuspense);
41
+ export const ViewEditModal = lazy(() => import("./ViewEditModal"), withSuspense);
42
+ export const Edit = lazy(() => import("./Edit"), withSuspense);
43
+ export const New = lazy(() => import("./New"), withSuspense);
44
+ export const AdminPanel = lazy(() => import("./AdminPanel"), bodyFallback);
package/ui/ObjectId.tsx CHANGED
@@ -4,6 +4,7 @@ import { AiOutlineCheck, AiOutlineCopy } from "react-icons/ai";
4
4
 
5
5
  import { buttonRecipe } from "./Button";
6
6
  import { Tooltip } from "./Tooltip";
7
+ import { useUiRecipe } from "./UiOverride";
7
8
 
8
9
  interface ObjectIdProps {
9
10
  id: string;
@@ -11,6 +12,7 @@ interface ObjectIdProps {
11
12
 
12
13
  export const ObjectId = ({ id }: ObjectIdProps) => {
13
14
  const [isCopied, setIsCopied] = useState(false);
15
+ const recipe = useUiRecipe("button") ?? buttonRecipe;
14
16
  const shortenedId = `${id.substring(0, 4)}...${id.substring(id.length - 5)}`;
15
17
  const handleCopyClick = () => {
16
18
  void navigator.clipboard.writeText(id);
@@ -24,10 +26,7 @@ export const ObjectId = ({ id }: ObjectIdProps) => {
24
26
  <Tooltip content={id} variant="primary">
25
27
  <div className="font-semibold text-xs">{shortenedId}</div>
26
28
  </Tooltip>
27
- <button
28
- className={buttonRecipe({ variant: "ghost", size: "icon" }, "size-6 rounded-full")}
29
- onClick={handleCopyClick}
30
- >
29
+ <button className={recipe({ variant: "ghost", size: "icon" }, "size-6 rounded-full")} onClick={handleCopyClick}>
31
30
  {isCopied ? <AiOutlineCheck /> : <AiOutlineCopy />}
32
31
  </button>
33
32
  </div>
package/ui/Pagination.tsx CHANGED
@@ -4,10 +4,7 @@ import type { FC, ReactNode } from "react";
4
4
  import { BiChevronLeft, BiChevronRight, BiDotsHorizontalRounded } from "react-icons/bi";
5
5
 
6
6
  import { buttonRecipe } from "./Button";
7
- import { createOverridable } from "./UiOverride";
8
-
9
- /** Square ghost button style shared by every pager control (canonical buttonRecipe). */
10
- const pageBtn = buttonRecipe({ variant: "ghost", size: "icon" });
7
+ import { createOverridable, useUiRecipe } from "./UiOverride";
11
8
 
12
9
  export interface PaginationProps {
13
10
  /** Current 1-based page number. */
@@ -36,6 +33,8 @@ export const DefaultPagination: FC<PaginationProps> = ({
36
33
  renderEmpty,
37
34
  classNames,
38
35
  }) => {
36
+
37
+ const pageBtn = (useUiRecipe("button") ?? buttonRecipe)({ variant: "ghost", size: "icon" });
39
38
  const totalPages = Math.ceil(total / (itemsPerPage || 1));
40
39
  const handleLeftClick = () => {
41
40
  if (currentPage <= 1) return;
package/ui/Popconfirm.tsx CHANGED
@@ -2,11 +2,12 @@
2
2
  import { useSpring } from "@react-spring/web";
3
3
 
4
4
  import { cn, usePage } from "akanjs/client";
5
+ import { useEscapeKey } from "akanjs/webkit";
5
6
  import { type ButtonHTMLAttributes, type ReactNode, useEffect, useState } from "react";
6
7
  import { BiMessageRoundedError } from "react-icons/bi";
7
8
  import { animated } from "./animated";
8
9
  import { buttonRecipe } from "./Button";
9
- import { createOverridable } from "./UiOverride";
10
+ import { createOverridable, useUiRecipe } from "./UiOverride";
10
11
 
11
12
  type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
12
13
  loading?: boolean;
@@ -48,6 +49,8 @@ export const DefaultPopconfirm = ({
48
49
  decoClassName,
49
50
  }: PopconfirmProps) => {
50
51
  const { l } = usePage();
52
+
53
+ const recipe = useUiRecipe("button") ?? buttonRecipe;
51
54
  const [isConfirming, setIsConfirming] = useState(false);
52
55
 
53
56
  const popconfirmProps = useSpring({
@@ -82,6 +85,8 @@ export const DefaultPopconfirm = ({
82
85
  setIsConfirming(false);
83
86
  };
84
87
 
88
+ useEscapeKey(isConfirming, handleCancel);
89
+
85
90
  return (
86
91
  <>
87
92
  <div className="relative inline-block">
@@ -115,17 +120,13 @@ export const DefaultPopconfirm = ({
115
120
  </div>
116
121
  <div className="flex justify-end gap-2">
117
122
  <button
118
- className={buttonRecipe({ variant: "outline", size: "xs" })}
123
+ className={recipe({ variant: "outline", size: "xs" })}
119
124
  onClick={handleCancel}
120
125
  {...cancelButtonProps}
121
126
  >
122
127
  {cancelText ?? l("base.cancel")}
123
128
  </button>
124
- <button
125
- className={buttonRecipe({ variant: "primary", size: "xs" })}
126
- onClick={handleConfirm}
127
- {...okButtonProps}
128
- >
129
+ <button className={recipe({ variant: "primary", size: "xs" })} onClick={handleConfirm} {...okButtonProps}>
129
130
  {okText ?? l("base.ok")}
130
131
  </button>
131
132
  </div>
package/ui/Select.tsx CHANGED
@@ -7,6 +7,7 @@ import { BiCheck, BiChevronDown, BiX } from "react-icons/bi";
7
7
  import { BsQuestionCircleFill } from "react-icons/bs";
8
8
  import { TiDelete } from "react-icons/ti";
9
9
 
10
+ import { agentAttrs } from "./agentAttrs";
10
11
  import { useUiOverride } from "./UiOverride";
11
12
 
12
13
  interface LabelOption<T> {
@@ -164,7 +165,7 @@ const DefaultSelect = <
164
165
  }, [value]);
165
166
 
166
167
  return (
167
- <div className={cn("relative min-w-[150px]", className)} ref={dropdownRef}>
168
+ <div {...agentAttrs(onChange)} className={cn("relative min-w-[150px]", className)} ref={dropdownRef}>
168
169
  <div
169
170
  data-open={isOpen}
170
171
  className={cn(
@@ -217,7 +218,7 @@ const DefaultSelect = <
217
218
  {searchable ? (
218
219
  <input
219
220
  type="text"
220
- className="input w-full flex-1 border-none bg-transparent shadow-none outline-none focus:border-none focus:shadow-none focus:outline-none"
221
+ className="w-full flex-1 border-none bg-transparent shadow-none outline-none focus:border-none focus:shadow-none focus:outline-none"
221
222
  placeholder={selectedValues.length > 0 ? "" : placeholder}
222
223
  value={searchText}
223
224
  onChange={(e) => {
@@ -262,8 +263,9 @@ const DefaultSelect = <
262
263
  <div
263
264
  data-open={isOpen}
264
265
  className={cn(
265
- "scrollbar-thin scrollbar-thumb-foreground/20 scrollbar-track scrollbar-track-foreground/40 absolute z-20 mt-0.5 w-full overflow-y-scroll rounded-md border-border bg-muted shadow-lg transition-all",
266
- "origin-center duration-200 data-[open=false]:h-0 data-[open=true]:h-[270px] data-[open=true]:border data-[open=false]:border-none",
266
+ "scrollbar-thin scrollbar-thumb-foreground/20 scrollbar-track scrollbar-track-foreground/40 absolute z-20 mt-0.5 w-full overflow-y-auto rounded-md border-border bg-muted shadow-lg transition-all",
267
+
268
+ "origin-center duration-200 data-[open=false]:max-h-0 data-[open=true]:max-h-[270px] data-[open=true]:border data-[open=false]:border-none",
267
269
  selectorClassName,
268
270
  )}
269
271
  >
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { PrimitiveRegistry } from "akanjs/base";
3
3
  import { usePage } from "akanjs/client";
4
+ import { mcpHintsOf, mcpRefusalOf } from "akanjs/common";
4
5
  import { type ConstantCls, ConstantRegistry } from "akanjs/constant";
5
6
  import { FetchClient, type FetchProxy } from "akanjs/fetch";
6
7
  import type { SerializedEndpoint } from "akanjs/signal";
7
8
  import { st } from "akanjs/store";
8
9
  import { useMemo, useState } from "react";
9
10
  import { AiOutlineApi, AiOutlineCopy, AiOutlineFileWord, AiOutlineSend } from "react-icons/ai";
11
+ import { badgeRecipe } from "../Badge";
10
12
  import { buttonRecipe } from "../Button";
11
13
  import { Copy } from "../Copy";
12
14
  import { Signal } from ".";
@@ -14,7 +16,7 @@ import Arg from "./Arg";
14
16
  import { SignalCollapse } from "./Collapse";
15
17
  import { getExampleData } from "./makeExample";
16
18
  import Response from "./Response";
17
- import { getEndpointBadgeClassName, getGuardBadgeClassName, signalUi } from "./style";
19
+ import { getEndpointBadgeClassName, getGuardBadgeClassName, getMcpBadgeClassName, signalUi } from "./style";
18
20
 
19
21
  type RestApiFetchFn = (
20
22
  ...args: [...args: unknown[], option: { token?: string; crystalize?: boolean }]
@@ -36,17 +38,21 @@ const RestApiEndpoints = ({ refName, fetch, prefix, endpoints, openAll, httpUri
36
38
  const tryRoles = st.use.tryRoles();
37
39
  const signal = fetch.serializedSignal[refName];
38
40
  const signalPrefix = prefix ?? signal.prefix;
39
- const baseEndpointEntries = Object.entries(FetchClient.getBaseEndpoint(refName, signal));
40
- const sliceEndpointEntries = signal.slice
41
- ? Object.entries(signal.slice).flatMap(([suffix, slice]) => {
42
- const endpoint = FetchClient.getEndpointFromSlice(refName, suffix, slice);
43
- return Object.entries(endpoint);
44
- })
45
- : [];
46
- const endpointEntries = [...baseEndpointEntries, ...sliceEndpointEntries, ...Object.entries(signal.endpoint)]
47
- .filter(([key, endpoint]) => !endpoints || endpoints.includes(key))
48
- .sort(([keyA], [keyB]) => (keyA > keyB ? 1 : -1))
49
- .filter(([key, endpoint]) => {
41
+ const baseEndpointEntries = Object.entries(FetchClient.getBaseEndpoint(refName, signal)).map(([key, endpoint]) => ({
42
+ key,
43
+ endpoint,
44
+ }));
45
+ const sliceEndpointEntries = Object.entries(signal.slice ?? {}).flatMap(([suffix, slice]) =>
46
+ Object.entries(FetchClient.getEndpointFromSlice(refName, suffix, slice)).map(([key, endpoint]) => ({
47
+ key,
48
+ endpoint,
49
+ })),
50
+ );
51
+ const customEndpointEntries = Object.entries(signal.endpoint).map(([key, endpoint]) => ({ key, endpoint }));
52
+ const endpointEntries = [...baseEndpointEntries, ...sliceEndpointEntries, ...customEndpointEntries]
53
+ .filter(({ key }) => !endpoints || endpoints.includes(key))
54
+ .sort((a, b) => (a.key > b.key ? 1 : -1))
55
+ .filter(({ endpoint }) => {
50
56
  if (endpoint.type === "pubsub" || endpoint.type === "message") return false;
51
57
  if (!endpoint.guards?.length) return true;
52
58
  if (endpoint.guards?.includes("Public") && tryRoles.includes("Public")) return true;
@@ -63,13 +69,13 @@ const RestApiEndpoints = ({ refName, fetch, prefix, endpoints, openAll, httpUri
63
69
  });
64
70
  return (
65
71
  <div>
66
- {endpointEntries.map(([endpointKey, endpoint], idx) => (
72
+ {endpointEntries.map(({ key, endpoint }) => (
67
73
  <RestApiEndpoint
68
- key={endpointKey}
74
+ key={key}
69
75
  signalPrefix={signalPrefix}
70
76
  refName={refName}
71
77
  fetch={fetch}
72
- endpointKey={endpointKey}
78
+ endpointKey={key}
73
79
  endpoint={endpoint}
74
80
  open={openAll}
75
81
  httpUri={httpUri}
@@ -102,13 +108,20 @@ const RestApiEndpoint = ({
102
108
  const { l } = usePage();
103
109
  const [viewStatus, setViewStatus] = useState<"doc" | "test">("doc");
104
110
  const path = FetchClient.makeHttpUrl(endpointKey, endpoint, signalPrefix, new Map());
111
+
112
+ const mcpRefusal = mcpRefusalOf(endpoint);
105
113
  return (
106
114
  <SignalCollapse
107
115
  open={open}
108
116
  contentClassName="bg-background/60"
109
117
  summary={
110
118
  <div className="flex flex-wrap items-center gap-2">
111
- <div className={getEndpointBadgeClassName(endpoint.type)}>{endpoint.type === "query" ? "GET" : "POST"}</div>
119
+ {/* Only a mutation is a POST — enumerate that side, because a `prompt` is a GET beside the queries and
120
+ a new read-shaped type would inherit the right verb rather than be mislabelled. */}
121
+ <div className={getEndpointBadgeClassName(endpoint.type)}>
122
+ {endpoint.type === "mutation" ? "POST" : "GET"}
123
+ </div>
124
+ <div className={getMcpBadgeClassName(!mcpRefusal)}>{mcpRefusal ? "MCP refused" : "MCP"}</div>
112
125
  <div className="font-bold text-lg">{path}</div>
113
126
  <div className="text-foreground/70 text-sm">{l._(`${refName}.signal.${endpointKey}`)}</div>
114
127
  </div>
@@ -127,6 +140,20 @@ const RestApiEndpoint = ({
127
140
  ))}
128
141
  </div>
129
142
  ) : null}
143
+ <div className="mt-2 flex flex-wrap items-center gap-2 font-normal text-sm">
144
+ <span className="text-foreground/70">MCP</span>
145
+ {mcpRefusal ? (
146
+ <span className="text-warning">{mcpRefusal}</span>
147
+ ) : (
148
+ Object.entries(mcpHintsOf(endpointKey, endpoint))
149
+ .filter(([, on]) => on)
150
+ .map(([hint]) => (
151
+ <span className={badgeRecipe({ variant: "outline", size: "sm" })} key={hint}>
152
+ {hint}
153
+ </span>
154
+ ))
155
+ )}
156
+ </div>
130
157
  <div className="mt-2 font-normal text-foreground/70 text-sm">
131
158
  {l._(`${refName}.signal.${endpointKey}.desc`)}
132
159
  </div>
@@ -18,7 +18,7 @@ const WebSocketEndpoints = ({ refName, fetch, openAll }: WebSocketEndpointsProps
18
18
  const endpointEntries = Object.entries(signal.endpoint)
19
19
  .sort(([keyA], [keyB]) => (keyA > keyB ? 1 : -1))
20
20
  .filter(([key, endpoint]) => {
21
- if (endpoint.type === "query" || endpoint.type === "mutation") return false;
21
+ if (endpoint.type !== "pubsub" && endpoint.type !== "message") return false;
22
22
 
23
23
  return false;
24
24
  });
@@ -15,12 +15,17 @@ export const signalUi = {
15
15
  "min-h-[300px] w-full rounded-xl border border-border bg-background p-4 font-normal text-foreground text-sm",
16
16
  };
17
17
 
18
+ /** Writes carry the accent, reads do not — so the two write types are named and everything else reads. */
18
19
  export const getEndpointBadgeClassName = (type: string) =>
19
- badgeRecipe({ variant: type === "query" || type === "pubsub" ? "primary" : "secondary" });
20
+ badgeRecipe({ variant: type === "mutation" || type === "message" ? "secondary" : "primary" });
20
21
 
21
22
  export const getGuardBadgeClassName = (guard: string) =>
22
23
  badgeRecipe({ variant: guard === "Public" ? "primary" : guard === "None" ? "default" : "secondary" });
23
24
 
25
+ /** Published to agents carries the accent; opted in and refused is outlined, because it is a thing to go fix. */
26
+ export const getMcpBadgeClassName = (exposed: boolean) =>
27
+ badgeRecipe({ variant: exposed ? "accent" : "warning", size: "sm", outline: !exposed });
28
+
24
29
  export const getStatusBadgeClassName = (status: string) =>
25
30
  badgeRecipe({
26
31
  variant: status === "error" ? "error" : status === "success" || status === "listening" ? "primary" : "outline",
package/ui/Switch.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "akanjs/client";
3
3
  import { useState } from "react";
4
+ import { agentAttrs } from "./agentAttrs";
4
5
 
5
6
  export interface SwitchProps {
6
7
  checked?: boolean;
@@ -36,6 +37,7 @@ export const Switch = ({
36
37
  const state = isChecked ? "checked" : "unchecked";
37
38
  return (
38
39
  <button
40
+ {...agentAttrs(onChange)}
39
41
  type="button"
40
42
  role="switch"
41
43
  aria-checked={isChecked}
package/ui/System/CSR.tsx CHANGED
@@ -226,6 +226,7 @@ const CSRWrapper = ({
226
226
  : bottomInset?.containerStyle
227
227
  }
228
228
  animationDuration={frameLayout.keyboard.animationDuration}
229
+ animationEasing={frameLayout.keyboard.animationEasing}
229
230
  >
230
231
  <CSRFrameSlotTargets slot="keyboardInset" />
231
232
  </KeyboardLayer>
@@ -281,14 +282,17 @@ const KeyboardLayer = ({
281
282
  className,
282
283
  style,
283
284
  animationDuration,
285
+ animationEasing,
284
286
  children,
285
- }: FrameLayerProps & { animationDuration?: number }) => (
287
+ }: FrameLayerProps & { animationDuration?: number; animationEasing?: string }) => (
286
288
  <animated.div
287
289
  id={id}
288
290
  className={className}
289
291
  style={{
290
292
  ...(style ?? {}),
291
- transition: `top ${animationDuration ?? 285}ms ease-out, height ${animationDuration ?? 285}ms ease-out`,
293
+ transition: `top ${animationDuration ?? 420}ms ${animationEasing ?? "cubic-bezier(0.16, 1, 0.3, 1)"}, height ${
294
+ animationDuration ?? 420
295
+ }ms ${animationEasing ?? "cubic-bezier(0.16, 1, 0.3, 1)"}`,
292
296
  willChange: "top, height",
293
297
  }}
294
298
  >
@@ -1,18 +1,35 @@
1
1
  "use client";
2
2
 
3
3
  import { setCookie } from "akanjs/client";
4
+ import { st } from "akanjs/store";
4
5
  import { useCallback, useEffect, useState } from "react";
5
-
6
6
  import { buttonRecipe } from "../Button";
7
7
  import { Dropdown } from "../Dropdown";
8
8
  import { Switch } from "../Switch";
9
9
 
10
+ interface ThemeAgentSurfaceProps {
11
+ themes: string[];
12
+ current?: string;
13
+ onApply: (theme: string) => void;
14
+ }
15
+ const ThemeAgentSurface = ({ themes, current, onApply }: ThemeAgentSurfaceProps) => {
16
+ st.expose("theme", current ?? null);
17
+ st.tool("setTheme", { desc: `Switch this page's color theme. One of: ${themes.join(", ")}.` })
18
+ .arg("theme", String)
19
+ .exec((theme) => {
20
+ if (!themes.includes(theme)) throw new Error(`Unknown theme "${theme}". One of: ${themes.join(", ")}.`);
21
+ onApply(theme);
22
+ });
23
+ return null;
24
+ };
25
+
10
26
  export interface ThemeToggleProps {
11
27
  themes?: string[];
12
28
  }
13
29
 
14
30
  export const ThemeToggle = ({ themes }: ThemeToggleProps) => {
15
31
  const [theme, setTheme] = useState<string | undefined>(undefined);
32
+ const stTheme = st.use.theme();
16
33
  useEffect(() => {
17
34
  if (!themes) return;
18
35
  const currentTheme = document.documentElement.getAttribute("data-theme");
@@ -25,9 +42,11 @@ export const ThemeToggle = ({ themes }: ThemeToggleProps) => {
25
42
  setTheme(theme);
26
43
  }, []);
27
44
  if (!themes || themes.length <= 1) return null;
45
+ const agentSurface = <ThemeAgentSurface current={theme} onApply={applyTheme} themes={themes} />;
28
46
  if (themes.length === 2)
29
47
  return (
30
48
  <div className="flex items-center gap-1 text-foreground">
49
+ {agentSurface}
31
50
  <svg aria-label="sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" className="size-4">
32
51
  <g strokeLinejoin="round" strokeLinecap="round" strokeWidth="2" fill="none" stroke="currentColor">
33
52
  <circle cx="12" cy="12" r="4"></circle>
@@ -55,37 +74,40 @@ export const ThemeToggle = ({ themes }: ThemeToggleProps) => {
55
74
  </div>
56
75
  );
57
76
  return (
58
- <Dropdown
59
- className="mb-72"
60
- buttonClassName="m-1"
61
- value={
62
- <>
63
- Theme
64
- <svg
65
- width="12px"
66
- height="12px"
67
- className="inline-block h-2 w-2 fill-current opacity-60"
68
- xmlns="http://www.w3.org/2000/svg"
69
- viewBox="0 0 2048 2048"
70
- >
71
- <path d="M1799 349l242 241-1017 1017L7 590l242-241 775 775 775-775z"></path>
72
- </svg>
73
- </>
74
- }
75
- dropdownClassName="w-52 bg-border"
76
- content={themes.map((theme) => (
77
- <li key={theme}>
78
- <button
79
- type="button"
80
- className={buttonRecipe({ variant: "ghost", size: "sm" }, "w-full justify-start")}
81
- onClick={() => {
82
- applyTheme(theme);
83
- }}
84
- >
85
- {theme}
86
- </button>
87
- </li>
88
- ))}
89
- />
77
+ <>
78
+ {agentSurface}
79
+ <Dropdown
80
+ className="mb-72"
81
+ buttonClassName="m-1"
82
+ value={
83
+ <>
84
+ Theme
85
+ <svg
86
+ width="12px"
87
+ height="12px"
88
+ className="inline-block h-2 w-2 fill-current opacity-60"
89
+ xmlns="http://www.w3.org/2000/svg"
90
+ viewBox="0 0 2048 2048"
91
+ >
92
+ <path d="M1799 349l242 241-1017 1017L7 590l242-241 775 775 775-775z"></path>
93
+ </svg>
94
+ </>
95
+ }
96
+ dropdownClassName="w-52 bg-border"
97
+ content={themes.map((theme) => (
98
+ <li key={theme}>
99
+ <button
100
+ type="button"
101
+ className={buttonRecipe({ variant: "ghost", size: "sm" }, "w-full justify-start")}
102
+ onClick={() => {
103
+ applyTheme(theme);
104
+ }}
105
+ >
106
+ {theme}
107
+ </button>
108
+ </li>
109
+ ))}
110
+ />
111
+ </>
90
112
  );
91
113
  };
@@ -3,10 +3,9 @@ import { cn, usePage } from "akanjs/client";
3
3
  import { type ComponentType, createElement } from "react";
4
4
 
5
5
  import { buttonRecipe } from "./Button";
6
- import { createOverridable, useUiOverride } from "./UiOverride";
6
+ import { createOverridable, useUiOverride, useUiRecipe } from "./UiOverride";
7
7
 
8
- /** Toggle-select cell: outline button, filled success when selected. */
9
- const toggleBtn = buttonRecipe({ variant: "outline", size: "sm" });
8
+ /** Toggle-select cell: outline button (recipe slot), filled success when selected. */
10
9
  const selectedCls = "border-transparent bg-success/70 text-success-foreground hover:bg-success/70";
11
10
 
12
11
  export interface ToggleSelectProps<I extends string | number | boolean | null> {
@@ -30,6 +29,7 @@ const DefaultToggleSelect = <I extends string | number | boolean | null>({
30
29
  disabled,
31
30
  }: ToggleSelectProps<I>) => {
32
31
  const { l } = usePage();
32
+ const toggleBtn = (useUiRecipe("button") ?? buttonRecipe)({ variant: "outline", size: "sm" });
33
33
  const validateResult = value !== null ? validate(value) : false;
34
34
 
35
35
  const invalidMessage =
@@ -97,6 +97,7 @@ const DefaultMulti = ({
97
97
  disabled,
98
98
  }: MultiProps) => {
99
99
  const { l } = usePage();
100
+ const toggleBtn = (useUiRecipe("button") ?? buttonRecipe)({ variant: "outline", size: "sm" });
100
101
  const validateResult = validate(value);
101
102
 
102
103
  const invalidMessage =
package/ui/Tooltip.tsx CHANGED
@@ -35,7 +35,8 @@ const sideClass = {
35
35
  const DefaultTooltip = ({ content, children, side = "top", className, variant = "default" }: TooltipProps) => {
36
36
  if (content === undefined || content === null || content === "") return <>{children}</>;
37
37
  return (
38
- <span className="group/tooltip relative inline-flex">
38
+
39
+ <span className="group/tooltip relative inline-flex w-fit">
39
40
  {children}
40
41
  <span
41
42
  role="tooltip"
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { type ComponentType, createContext } from "react";
3
3
  import type { ClassNameValue as ClassValue } from "tailwind-merge";
4
+ import type { ChatProps as AgentChatProps } from "../Agent/Chat";
4
5
  import type { BadgeProps } from "../Badge";
5
6
  import type { ButtonProps } from "../Button";
6
7
  import type { DatePickerProps, RangePickerProps, TimePickerProps } from "../DatePicker";
@@ -17,7 +18,7 @@ import type { ModalProps } from "../Modal";
17
18
  import type { PaginationProps } from "../Pagination";
18
19
  import type { PopconfirmProps } from "../Popconfirm";
19
20
  import type { ItemProps as RadioItemProps, RadioProps } from "../Radio";
20
- import type { BadgeVariants, ButtonVariants } from "../recipe";
21
+ import type { BadgeVariants, ButtonVariants, InputSurfaceVariants } from "../recipe";
21
22
  import type { SelectProps } from "../Select";
22
23
  import type { TableProps } from "../Table";
23
24
  import type { MultiProps as ToggleSelectMultiProps, ToggleSelectProps } from "../ToggleSelect";
@@ -48,6 +49,7 @@ export interface AkanUiOverrides {
48
49
  Menu: ComponentType<MenuProps>;
49
50
  Tooltip: ComponentType<TooltipProps>;
50
51
  Unauthorized: ComponentType<UnauthorizedProps>;
52
+ AgentChat: ComponentType<AgentChatProps>;
51
53
 
52
54
  Button: ComponentType<ButtonProps<unknown>>;
53
55
  Select: ComponentType<SelectProps<string | number | boolean | null | undefined>>;
@@ -87,11 +89,21 @@ export type AkanModalComponent = AkanUiOverrides["Modal"];
87
89
  * manifest: `override({ recipes: { button: neonButtonRecipe } })`. A recipe swap changes
88
90
  * only the className factory — the component's structure/behavior (async states, focus,
89
91
  * a11y) is untouched. Each replacement must accept the framework recipe's full variant
90
- * contract, so every call site keeps working.
92
+ * contract, so every call site keeps working (a replacement with *extra* optional axes is
93
+ * assignable — contravariance — but those axes are only reachable from code that knows the
94
+ * replacement's own type).
95
+ *
96
+ * Scope: a recipe slot is a **client-side, route-scoped restyle**. It reaches framework
97
+ * client components, which resolve through `useUiRecipe(...)`. It never reaches a raw
98
+ * `xRecipe(...)` call in app JSX (statically imported — no context), nor server components
99
+ * (`Unit`/`View`), which intentionally render the canonical framework recipe. Extending the
100
+ * *vocabulary* is not this slot's job: add the axis to the framework recipe, or author an
101
+ * app recipe in `apps/<app>/ui/Recipe/`.
91
102
  */
92
103
  export interface AkanUiRecipes {
93
104
  button: (variants?: ButtonVariants, className?: ClassValue) => string;
94
105
  badge: (variants?: BadgeVariants, className?: ClassValue) => string;
106
+ input: (variants?: InputSurfaceVariants, className?: ClassValue) => string;
95
107
  }
96
108
 
97
109
  /** Shape of an `_overrides.tsx` manifest: component slots plus an optional recipe-slot map. */
@@ -0,0 +1,19 @@
1
+ import { actionTagOf } from "akanjs/store";
2
+
3
+ /**
4
+ * The `data-akan-*` attributes for a handler the caller passed by reference.
5
+ *
6
+ * `{}` when the handler is an inline arrow, which is the honest answer: a closure the caller wrote says nothing
7
+ * about what it does, and a guessed annotation is worse than none. The house form for a model field is the setter
8
+ * itself (`onChange={st.do.setNameOnUser}`), so the fields that matter are annotated without an app writing anything.
9
+ *
10
+ * What it buys, beyond an in-page agent: an accessibility tree and E2E selectors that name the action rather than a
11
+ * class, and an external browser agent — one this framework has no bridge into — reading the same names.
12
+ */
13
+ export const agentAttrs = (
14
+ handler: unknown,
15
+ ): { "data-akan-action"?: string; "data-akan-state"?: string } | Record<string, never> => {
16
+ const tag = actionTagOf(handler);
17
+ if (!tag) return {};
18
+ return { "data-akan-action": tag.action, ...(tag.state ? { "data-akan-state": tag.state } : {}) };
19
+ };