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
@@ -0,0 +1,122 @@
1
+ import { router } from "akanjs/client";
2
+ import type { SurfaceSource, ToolEntry } from "../../vendor/use-agentic";
3
+ import { AgentBridge, type AgentTool } from "./AgentBridge";
4
+ import { ScreenReader } from "./ScreenReader";
5
+
6
+ /**
7
+ * The store bridge as one surface source: every catalogued action of the stores the rendered screen is reading is
8
+ * a callable tool, executed through `AgentBridge.call` so argument checking, masking, and the transcript stay in
9
+ * one place. Recomputed per snapshot — the bridge's live view changes as components mount and unmount — and
10
+ * per zone view: a zone session sees the stores its own subtree subscribes, and its `readScreen` reads its own
11
+ * `data-agent-zone` container rather than the whole document.
12
+ *
13
+ * `remove*` keys default to a confirm gate — destructiveness derived from the key, the way the MCP hints derive
14
+ * theirs — and a page can still shadow any entry with its own hook registration.
15
+ */
16
+ export class StoreSurfaceSource implements SurfaceSource {
17
+ #bridge: AgentBridge | null;
18
+ readonly #wrapped = new Map<string, { source: AgentTool[]; entries: ToolEntry[] }>();
19
+ readonly #builtins = new Map<string, ToolEntry[]>();
20
+
21
+ /** Lazy by default: `AgentBridge.of()` walks the whole store, so it waits for the first enumeration. */
22
+ constructor(bridge?: AgentBridge) {
23
+ this.#bridge = bridge ?? null;
24
+ }
25
+
26
+ tools = (view: string[] = []): ToolEntry[] => {
27
+ const viewKey = view.join(".");
28
+ this.#bridge ??= AgentBridge.of();
29
+ const bridge = this.#bridge;
30
+ const live = bridge.toolsFor(viewKey);
31
+ const cached = this.#wrapped.get(viewKey);
32
+ if (cached?.source !== live)
33
+ this.#wrapped.set(viewKey, {
34
+ source: live,
35
+ entries: live.map((tool) => StoreSurfaceSource.#entry(bridge, tool, viewKey)),
36
+ });
37
+
38
+ let builtins = this.#builtins.get(viewKey);
39
+ if (!builtins) {
40
+ builtins = [StoreSurfaceSource.#navigate(), StoreSurfaceSource.#readScreen(viewKey), this.#readState(viewKey)];
41
+ this.#builtins.set(viewKey, builtins);
42
+ }
43
+ const wrapped = this.#wrapped.get(viewKey);
44
+ return [...(wrapped?.entries ?? []), ...builtins];
45
+ };
46
+
47
+ static #entry(bridge: AgentBridge, tool: AgentTool, viewKey: string): ToolEntry {
48
+ const description = tool.description ?? tool.title;
49
+ return {
50
+ name: tool.name,
51
+ ...(description ? { description } : {}),
52
+ parameters: tool.inputSchema as Record<string, unknown>,
53
+ effect: tool.effect,
54
+ ...(tool.name.startsWith("remove") ? { confirm: true } : {}),
55
+ run: async (args: Record<string, unknown>) => {
56
+ await bridge.call(tool.name, args, viewKey);
57
+ },
58
+ };
59
+ }
60
+
61
+ /** Screen-driving is client navigation, so the agent gets the same router `Link` rides. */
62
+ static #navigate(): ToolEntry {
63
+ return {
64
+ name: "navigate",
65
+ description: "Navigate this page to an internal path of this app, e.g. /docs/intro/quickstart.",
66
+ parameters: {
67
+ type: "object",
68
+ properties: { path: { type: "string" } },
69
+ required: ["path"],
70
+ additionalProperties: false,
71
+ },
72
+ effect: "state",
73
+
74
+ guard: (args) =>
75
+ typeof args.path === "string" && args.path.startsWith("/") && !args.path.startsWith("//")
76
+ ? true
77
+ : "path must be an internal path starting with /.",
78
+ run: (args) => {
79
+ const path = String(args.path);
80
+ router.push(path);
81
+ return `Navigating to ${path}.`;
82
+ },
83
+ };
84
+ }
85
+
86
+ /** What the user is looking at, read from the rendered DOM — the store never held it, so no key can answer it. */
87
+ static #readScreen(viewKey: string): ToolEntry {
88
+ return {
89
+ name: "readScreen",
90
+ description: viewKey
91
+ ? "Read what is currently rendered in this zone — headings, prose, links, buttons, and form values. Use it when the user asks about what this zone shows."
92
+ : "Read what is currently rendered on this page — headings, prose, links, buttons, and form values. Use it when the user asks about the current page or screen.",
93
+ parameters: { type: "object", properties: {}, additionalProperties: false },
94
+ effect: "query",
95
+ run: () => ScreenReader.read(StoreSurfaceSource.#zoneRoot(viewKey)),
96
+ };
97
+ }
98
+
99
+ /** The pull half of the state context block: keys are listed there, values arrive masked through this. */
100
+ #readState(viewKey: string): ToolEntry {
101
+ return {
102
+ name: "readState",
103
+ description: "Read one store state key of this page. Keys are listed in the state context block.",
104
+ parameters: {
105
+ type: "object",
106
+ properties: { key: { type: "string" } },
107
+ required: ["key"],
108
+ additionalProperties: false,
109
+ },
110
+ effect: "state",
111
+ run: (args: Record<string, unknown>) => {
112
+ this.#bridge ??= AgentBridge.of();
113
+ return this.#bridge.read(String(args.key), viewKey);
114
+ },
115
+ };
116
+ }
117
+
118
+ static #zoneRoot(viewKey: string): HTMLElement | undefined {
119
+ if (!viewKey || typeof document === "undefined") return undefined;
120
+ return document.querySelector<HTMLElement>(`[data-agent-zone="${CSS.escape(viewKey)}"]`) ?? undefined;
121
+ }
122
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./AgentBridge";
2
+ export * from "./AgentContext";
3
+ export * from "./AgentPrompts";
4
+ export * from "./AgentVisibility";
5
+ export * from "./ScreenReader";
6
+ export * from "./StoreCatalogue";
7
+ export * from "./StoreSurfaceSource";
8
+ export * from "./storeSurface";
9
+ export * from "./types";
@@ -0,0 +1,28 @@
1
+ import { AgenticSurface } from "../../vendor/use-agentic";
2
+ import { AgentBridge } from "./AgentBridge";
3
+ import { StoreSurfaceSource } from "./StoreSurfaceSource";
4
+
5
+ export interface StoreSurface {
6
+ bridge: AgentBridge;
7
+ source: StoreSurfaceSource;
8
+ surface: AgenticSurface;
9
+ }
10
+
11
+ const SURFACE_KEY = Symbol.for("akanjs.store.agentSurface");
12
+
13
+ /**
14
+ * Attaches the app's store catalogue to the shared surface, once per runtime, lazily — nothing pays for the
15
+ * bridge walk until something agent-facing (the dock, a chat) actually asks. On the server it builds but does not
16
+ * attach: a server-global surface would be shared across requests, and no session assembles context there.
17
+ */
18
+ export const ensureStoreSurface = (): StoreSurface => {
19
+ const holder = globalThis as typeof globalThis & { [SURFACE_KEY]?: StoreSurface };
20
+ if (!holder[SURFACE_KEY]) {
21
+ const bridge = AgentBridge.of();
22
+ const source = new StoreSurfaceSource(bridge);
23
+ const surface = AgenticSurface.shared;
24
+ if (typeof window !== "undefined") surface.addSource(source);
25
+ holder[SURFACE_KEY] = { bridge, source, surface };
26
+ }
27
+ return holder[SURFACE_KEY];
28
+ };
@@ -0,0 +1,50 @@
1
+ import type { SerializedArg } from "akanjs/signal";
2
+ import type { SliceActionKey } from "../sliceRole";
3
+ import type { SliceStateKey } from "../state";
4
+
5
+ /** Which generated form-setter a store key is, when it is one. */
6
+ export type FormSetterRole = "set" | "add" | "sub" | "addOrSub";
7
+
8
+ /** What calling a store action reaches. `state` never leaves the browser. */
9
+ export type StoreActionEffect = "state" | "query" | "mutation";
10
+
11
+ export interface SerializedStoreAction {
12
+ args: SerializedArg[];
13
+ effect: StoreActionEffect;
14
+ /** The model this key belongs to, when the key identifies one. */
15
+ refName?: string;
16
+ /** The endpoint whose arguments it borrows, when it is named after one. */
17
+ endpoint?: string;
18
+ /** The generated role, absent on an action a module wrote itself. */
19
+ role?: SliceActionKey | FormSetterRole;
20
+ /** The model field it writes, on a form setter. */
21
+ field?: string;
22
+ }
23
+
24
+ export interface SerializedStoreState {
25
+ /**
26
+ * What the live value is. A store declares no types — `STATE_META` holds initial values — so this is read off the
27
+ * value the store is holding, and a key initialized to `null` or `[]` says nothing about what may go into it.
28
+ */
29
+ type: "string" | "number" | "boolean" | "date" | "list" | "map" | "object" | "unknown";
30
+ /** The model this key holds, when it holds one. What a read of it is masked by. */
31
+ refName?: string;
32
+ /** Which of the model's five classes, which is what decides the fields a read may carry. */
33
+ modelType?: "input" | "full" | "light" | "insight";
34
+ /** Materialized from a computation, the URL, or storage. Writing one throws, so it is read-only by construction. */
35
+ derived: boolean;
36
+ role?: SliceStateKey;
37
+ }
38
+
39
+ /**
40
+ * One store instance described for an agent: every key it can read and every action it may call.
41
+ *
42
+ * Flat rather than grouped by model, because that is what the store is — `st.use.x` and `st.do.y` are one namespace,
43
+ * so a key means the same thing to every reader and two models cannot both claim one. It is the store's answer to
44
+ * `SerializedSignal`, and it is derived on the client from the built store rather than shipped from the server: the
45
+ * store classes are in the bundle already, and a second copy over the wire is a second thing to keep in step.
46
+ */
47
+ export interface SerializedStore {
48
+ state: { [key: string]: SerializedStoreState };
49
+ action: { [key: string]: SerializedStoreAction };
50
+ }
@@ -0,0 +1,199 @@
1
+ import {
2
+ type CLIENT_VALUE,
3
+ type Cls,
4
+ dayjs,
5
+ type EnumInstance,
6
+ Int,
7
+ isEnum,
8
+ PrimitiveRegistry,
9
+ type PrimitiveScalar,
10
+ } from "akanjs/base";
11
+ import type { ParamFieldType } from "akanjs/constant";
12
+ import {
13
+ AgenticSurface,
14
+ type JsonSchema,
15
+ type ToolConfirm,
16
+ type ToolEffect,
17
+ type ToolGuard,
18
+ useScopePath,
19
+ useSurface,
20
+ } from "../../vendor/use-agentic";
21
+ import { tagAction } from "../actionTag";
22
+
23
+ import { useEffect, useRef } from "../hooks";
24
+
25
+ export interface StToolMeta {
26
+ desc?: string;
27
+ effect?: ToolEffect;
28
+ confirm?: ToolConfirm;
29
+ guard?: ToolGuard;
30
+ }
31
+
32
+ interface StToolArg {
33
+ name: string;
34
+ type: ParamFieldType;
35
+ optional: boolean;
36
+ }
37
+
38
+ type ArgValue<T> = T extends EnumInstance<string, infer V> ? V : T extends { [CLIENT_VALUE]: infer V } ? V : never;
39
+
40
+ /**
41
+ * A component tool in the signal's vocabulary: `st.tool("x", { desc }).arg("id", ID).exec(fn)`.
42
+ *
43
+ * This is not A12's rejected store-action builder — a store action derives its schema from the endpoint it is
44
+ * named after, while a component tool exists nowhere else, so declaring is the only source there is. `.arg()` only
45
+ * accumulates data; `.exec()` is the one hook, so the chain must complete in one unconditional statement.
46
+ */
47
+ export class StToolBuilder<Args extends unknown[] = []> {
48
+ readonly #name: string;
49
+ readonly #meta: StToolMeta;
50
+ readonly #args: StToolArg[];
51
+
52
+ constructor(name: string, meta: StToolMeta = {}, args: StToolArg[] = []) {
53
+ this.#name = name;
54
+ this.#meta = meta;
55
+ this.#args = args;
56
+ }
57
+
58
+ arg<T extends ParamFieldType>(name: string, type: T): StToolBuilder<[...Args, ArgValue<T>]>;
59
+ arg<T extends ParamFieldType>(
60
+ name: string,
61
+ type: T,
62
+ option: { optional: true },
63
+ ): StToolBuilder<[...Args, ArgValue<T> | null]>;
64
+ arg<T extends ParamFieldType>(
65
+ name: string,
66
+ type: T,
67
+ option: { optional?: boolean } = {},
68
+ ): StToolBuilder<[...Args, ArgValue<T> | null]> {
69
+
70
+ StToolBuilder.schemaOf(type);
71
+ return new StToolBuilder(this.#name, this.#meta, [...this.#args, { name, type, optional: !!option.optional }]);
72
+ }
73
+
74
+ /** The only hook in the chain. `run`, `guard`, and `confirm` stay always-latest; the declaration is mount-static. */
75
+ exec(run: (...args: Args) => unknown): (...args: Args) => Promise<void> {
76
+ const surface = useSurface();
77
+ const scope = useScopePath();
78
+ const live = useRef({ run, meta: this.#meta });
79
+ live.current = { run, meta: this.#meta };
80
+ const declared = useRef<{ name: string; meta: StToolMeta; args: StToolArg[] } | null>(null);
81
+ declared.current ??= { name: this.#name, meta: this.#meta, args: this.#args };
82
+ const callable = useRef<((...args: Args) => Promise<void>) | null>(null);
83
+ if (!callable.current) {
84
+ const action = AgenticSurface.fullName(scope, this.#name);
85
+ callable.current = tagAction(
86
+ async (...args: Args) => {
87
+ await live.current.run(...args);
88
+ },
89
+ { action },
90
+ );
91
+ }
92
+ const scopeKey = scope.join(".");
93
+ useEffect(() => {
94
+ const spec = declared.current;
95
+ if (!spec) return;
96
+ return surface.registerTool(scope, {
97
+ name: spec.name,
98
+ description: spec.meta.desc,
99
+ effect: spec.meta.effect,
100
+ parameters: StToolBuilder.parametersOf(spec.args),
101
+ ...(spec.meta.confirm === undefined
102
+ ? {}
103
+ : {
104
+ confirm: (args: Record<string, unknown>) => {
105
+ const confirm = live.current.meta.confirm;
106
+ return typeof confirm === "function" ? confirm(args) : (confirm ?? false);
107
+ },
108
+ }),
109
+ ...(spec.meta.guard === undefined
110
+ ? {}
111
+ : { guard: (args: Record<string, unknown>) => live.current.meta.guard?.(args) ?? true }),
112
+ run: (named) => live.current.run(...(StToolBuilder.positionalOf(spec.name, spec.args, named) as Args)),
113
+ });
114
+ }, [surface, scopeKey, this.#name]);
115
+ return callable.current;
116
+ }
117
+
118
+ static parametersOf(args: StToolArg[]): JsonSchema | undefined {
119
+ if (!args.length) return undefined;
120
+ const required = args.filter((arg) => !arg.optional).map((arg) => arg.name);
121
+ return {
122
+ type: "object",
123
+ properties: Object.fromEntries(args.map((arg) => [arg.name, StToolBuilder.schemaOf(arg.type)])),
124
+ ...(required.length ? { required } : {}),
125
+ additionalProperties: false,
126
+ };
127
+ }
128
+
129
+ /** Scalars and enums only — the value arrives as JSON from a model, so a class instance has no way in. */
130
+ static schemaOf(type: ParamFieldType): JsonSchema {
131
+ if (isEnum(type as Cls)) {
132
+ const enumRef = type as EnumInstance;
133
+ const kind = enumRef.type === String ? "string" : enumRef.type === Int ? "integer" : "number";
134
+ return { type: kind, enum: [...enumRef.values] };
135
+ }
136
+ const scalar = type as typeof PrimitiveScalar;
137
+ if (!PrimitiveRegistry.has(scalar as unknown as Cls))
138
+ throw new Error("st.tool takes scalar and enum arguments only.");
139
+ switch (PrimitiveRegistry.getName(scalar)) {
140
+ case "ID":
141
+ case "String":
142
+ return { type: "string" };
143
+ case "Int":
144
+ return { type: "integer" };
145
+ case "Float":
146
+ return { type: "number" };
147
+ case "Boolean":
148
+ return { type: "boolean" };
149
+ case "Date":
150
+ return { type: "string", format: "date-time" };
151
+ default:
152
+ throw new Error(`st.tool cannot describe the scalar ${PrimitiveRegistry.getName(scalar)}.`);
153
+ }
154
+ }
155
+
156
+ static positionalOf(toolName: string, args: StToolArg[], named: Record<string, unknown>): unknown[] {
157
+ return args.map((arg) => {
158
+ const value = named[arg.name];
159
+ if (value === undefined || value === null) {
160
+ if (arg.optional) return null;
161
+ throw new Error(`Missing argument "${arg.name}" for ${toolName}.`);
162
+ }
163
+ return StToolBuilder.checkedValue(toolName, arg.name, arg.type, value);
164
+ });
165
+ }
166
+
167
+ /** What `AgentBridge` does for endpoint arguments, for a component tool's own — nothing on the wire enforces the published schema. */
168
+ static checkedValue(toolName: string, argName: string, type: ParamFieldType, value: unknown): unknown {
169
+ if (isEnum(type as Cls)) {
170
+ const enumRef = type as EnumInstance;
171
+ if (!enumRef.values.includes(value as never))
172
+ throw new Error(`Argument "${argName}" of ${toolName} must be one of: ${[...enumRef.values].join(", ")}.`);
173
+ return value;
174
+ }
175
+ switch (PrimitiveRegistry.getName(type as typeof PrimitiveScalar)) {
176
+ case "ID":
177
+ case "String":
178
+ if (typeof value !== "string") throw new Error(`Argument "${argName}" of ${toolName} must be a string.`);
179
+ return value;
180
+ case "Int":
181
+ if (!Number.isInteger(value)) throw new Error(`Argument "${argName}" of ${toolName} must be a whole number.`);
182
+ return value;
183
+ case "Float":
184
+ if (typeof value !== "number" || !Number.isFinite(value))
185
+ throw new Error(`Argument "${argName}" of ${toolName} must be a finite number.`);
186
+ return value;
187
+ case "Boolean":
188
+ if (typeof value !== "boolean") throw new Error(`Argument "${argName}" of ${toolName} must be a boolean.`);
189
+ return value;
190
+ case "Date": {
191
+ const parsed = dayjs(value as string | number | Date);
192
+ if (!parsed.isValid()) throw new Error(`Argument "${argName}" of ${toolName} must be an ISO 8601 date string.`);
193
+ return parsed;
194
+ }
195
+ default:
196
+ return value;
197
+ }
198
+ }
199
+ }
@@ -0,0 +1,22 @@
1
+ import type { Dispatch, SetStateAction } from "react";
2
+ import { StToolBuilder, type StToolMeta } from "./StToolBuilder";
3
+ import { type StExposeMeta, useStExpose } from "./useStExpose";
4
+ import { type StStateMeta, useStState } from "./useStState";
5
+
6
+ export interface StAgentic {
7
+ /** Local state the in-page agent can read. Writes need a `set` type and go through a named setter tool. */
8
+ useState: <T>(name: string, initial: T | (() => T), meta?: StStateMeta<T>) => [T, Dispatch<SetStateAction<T>>];
9
+ /** A read-only derived value the agent can read while the component is mounted. */
10
+ expose: (name: string, value: unknown, meta?: StExposeMeta) => void;
11
+ /** A component tool: `.arg("id", ID)` chained onto one `.exec()` hook. */
12
+ tool: (name: string, meta?: StToolMeta) => StToolBuilder;
13
+ }
14
+
15
+ const stAgentic: StAgentic = {
16
+ useState: useStState,
17
+ expose: useStExpose,
18
+ tool: (name, meta) => new StToolBuilder(name, meta),
19
+ };
20
+
21
+ /** Idempotent — `StoreRegistry.build` runs once per merged root, always onto the one instance. */
22
+ export const attachAgentic = <T extends object>(instance: T): T & StAgentic => Object.assign(instance, stAgentic);
@@ -0,0 +1,5 @@
1
+ export * from "./attachAgentic";
2
+ export * from "./readableValue";
3
+ export * from "./StToolBuilder";
4
+ export * from "./useStExpose";
5
+ export * from "./useStState";
@@ -0,0 +1,17 @@
1
+ import { type MaskModel, mask } from "akanjs/constant";
2
+
3
+ const isPlainAgentValue = (value: unknown): boolean => {
4
+ if (value === null || value === undefined) return true;
5
+ if (Array.isArray(value)) return value.every((item) => isPlainAgentValue(item));
6
+ if (value instanceof Date) return true;
7
+ return typeof value !== "object";
8
+ };
9
+
10
+ /** What `AgentBridge.read` does for store keys, for a hook's value: mask by the declared model, pass scalars, refuse the rest. */
11
+ export const readableValue = (name: string, value: unknown, model?: MaskModel): unknown => {
12
+ if (model) return mask(model, value);
13
+ if (isPlainAgentValue(value)) return value;
14
+ throw new Error(
15
+ `State "${name}" holds an object that belongs to no model, so there is nothing to mask it by and it is not published. Declare mask: or serialize: on it.`,
16
+ );
17
+ };
@@ -0,0 +1,18 @@
1
+ import type { MaskModel } from "akanjs/constant";
2
+ import { useAgentResource } from "../../vendor/use-agentic";
3
+ import { readableValue } from "./readableValue";
4
+
5
+ export interface StExposeMeta {
6
+ desc?: string;
7
+ mask?: MaskModel;
8
+ serialize?: (value: unknown) => unknown;
9
+ report?: boolean;
10
+ }
11
+
12
+ export const useStExpose = (name: string, value: unknown, meta: StExposeMeta = {}): void => {
13
+ useAgentResource(name, value, {
14
+ description: meta.desc,
15
+ report: meta.report,
16
+ serialize: meta.serialize ?? ((current) => readableValue(name, current, meta.mask)),
17
+ });
18
+ };
@@ -0,0 +1,35 @@
1
+ import { capitalize } from "akanjs/common";
2
+ import type { MaskModel, ParamFieldType } from "akanjs/constant";
3
+ import type { Dispatch, SetStateAction } from "react";
4
+ import { useAgentState } from "../../vendor/use-agentic";
5
+ import { readableValue } from "./readableValue";
6
+ import { StToolBuilder } from "./StToolBuilder";
7
+
8
+ export interface StStateMeta<T> {
9
+ desc?: string;
10
+ /** The model whose `hidden`/`secret` fields a read strips. An object value with no `mask` and no `serialize` is refused. */
11
+ mask?: MaskModel;
12
+ serialize?: (value: T) => unknown;
13
+ report?: boolean;
14
+ /** The scalar or enum an agent may write through the generated `set<Name>` tool. Read-only without it. */
15
+ set?: ParamFieldType;
16
+ }
17
+
18
+ export const useStState = <T>(
19
+ name: string,
20
+ initial: T | (() => T),
21
+ meta: StStateMeta<T> = {},
22
+ ): [T, Dispatch<SetStateAction<T>>] => {
23
+ const set = meta.set;
24
+ return useAgentState<T>(name, initial, {
25
+ description: meta.desc,
26
+ report: meta.report,
27
+ serialize: meta.serialize ?? ((value) => readableValue(name, value, meta.mask)),
28
+ ...(set
29
+ ? {
30
+ set: StToolBuilder.schemaOf(set),
31
+ parse: (value) => StToolBuilder.checkedValue(`set${capitalize(name)}`, "value", set, value) as T,
32
+ }
33
+ : {}),
34
+ });
35
+ };
package/store/baseSt.ts CHANGED
@@ -19,6 +19,12 @@ export const getBaseSearchParam = (searchParams: BaseSearchParamsState, key: str
19
19
  return Array.isArray(value) ? value[0] : value;
20
20
  };
21
21
 
22
+ /**
23
+ * `agent: false` keeps the whole base store off the agent surface. Its keys are framework plumbing that other
24
+ * effects write into, so the generated setters are levers that do nothing (`setPath` does not navigate — the
25
+ * router overwrites it) — and `tryJwt`/`tryAccount` hold the caller's credential, which must never reach a model.
26
+ * The route context block carries the three keys an agent legitimately needs.
27
+ */
22
28
  export class BaseStore extends store("base" as const, () => ({
23
29
  csrLoaded: false,
24
30
  path: "/",
@@ -52,6 +58,7 @@ export class BaseStore extends store("base" as const, () => ({
52
58
  deviceToken: "" as string,
53
59
  currentPath: "" as string,
54
60
  })) {
61
+ static override agent = false as const;
55
62
  setDevMode(value: boolean) {
56
63
  this.set({ devMode: value });
57
64
  localStorage.setItem("devMode", value.toString());
@@ -0,0 +1,31 @@
1
+ import { capitalize } from "akanjs/common";
2
+
3
+ /**
4
+ * The state keys every model store holds, and which of the model's five classes each one is an instance of.
5
+ *
6
+ * Shared with the agent catalogue, which needs the class rather than the key: a value read out of the store is
7
+ * masked by the model it belongs to, and `immerify` drops the constructor, so the live value cannot say what it is.
8
+ * `modelForm` is the one that matters most — it is an `Input` holding whatever the user has typed, credentials
9
+ * included, and it reaches the catalogue as a plain object.
10
+ */
11
+ export const databaseStateNames = (refName: string) => {
12
+ const className = capitalize(refName);
13
+ return {
14
+ model: refName,
15
+ modelLoading: `${refName}Loading`,
16
+ modelForm: `${refName}Form`,
17
+ modelFormLoading: `${refName}FormLoading`,
18
+ modelSubmit: `${refName}Submit`,
19
+ modelViewAt: `${refName}ViewAt`,
20
+ modelModal: `${refName}Modal`,
21
+ modelOperation: `${refName}Operation`,
22
+ defaultModel: `default${className}`,
23
+ };
24
+ };
25
+
26
+ /** Which of the model's classes each generated state key holds, for the keys that hold one at all. */
27
+ export const databaseStateModelTypes = {
28
+ model: "full",
29
+ modelForm: "input",
30
+ defaultModel: "full",
31
+ } as const satisfies { [key in keyof ReturnType<typeof databaseStateNames>]?: "full" | "input" | "light" | "insight" };
@@ -0,0 +1,21 @@
1
+ import { capitalize, lowerlize } from "akanjs/common";
2
+
3
+ /**
4
+ * The keys `makeFormSetter` publishes for one field of one model.
5
+ *
6
+ * Shared with the agent catalogue, which has to answer what `setNameOnUser` takes without parsing the name apart —
7
+ * `set(.+)On(.+)` has more than one reading whenever a field or a model name contains `On`. Computing the same names
8
+ * forward from the same field metadata is unambiguous, and keeps the two from drifting when a name changes here.
9
+ */
10
+ export const formSetterNames = (className: string, key: string) => {
11
+ const classKeyName = capitalize(key);
12
+ return {
13
+ field: lowerlize(key),
14
+ Field: classKeyName,
15
+ setFieldOnModel: `set${classKeyName}On${className}`,
16
+ addFieldOnModel: `add${classKeyName}On${className}`,
17
+ subFieldOnModel: `sub${classKeyName}On${className}`,
18
+ addOrSubFieldOnModel: `addOrSub${classKeyName}On${className}`,
19
+ uploadFieldOnModel: `upload${classKeyName}On${className}`,
20
+ };
21
+ };
package/store/index.ts CHANGED
@@ -1,8 +1,16 @@
1
1
  export * from "./action";
2
+ export * from "./actionTag";
3
+ export * from "./agent";
4
+ export * from "./agentic";
2
5
  export * from "./baseSt";
6
+ export * from "./databaseStateNames";
7
+ export * from "./formSetterNames";
3
8
  export * from "./rootStore";
9
+ export * from "./sliceRole";
4
10
  export * from "./state";
5
11
  export * from "./stateBuilder";
6
12
  export * from "./store";
13
+
14
+ export { StoreInstance } from "./storeInstance";
7
15
  export * from "./storeRegistry";
8
16
  export * from "./types";
@@ -1,5 +1,6 @@
1
- import type { ACTION_META, Cls, STATE_DERIVED_META, STATE_INIT_META, STATE_META } from "akanjs/base";
1
+ import type { ACTION_META, ACTION_OWNER_META, Cls, STATE_DERIVED_META, STATE_INIT_META, STATE_META } from "akanjs/base";
2
2
  import type { SerializedSlice } from "akanjs/signal";
3
+ import type { ActionOwner } from "./actionTag";
3
4
  import type { StateDerivedMeta, StateInitializerMap } from "./stateBuilder";
4
5
  import type { SetGetWritable } from "./types";
5
6
 
@@ -20,6 +21,7 @@ export type RootStoreCls<
20
21
  [STATE_INIT_META]: StateInitializerMap;
21
22
  [STATE_DERIVED_META]: StateDerivedMeta;
22
23
  [ACTION_META]: { [key: string]: (...args: any[]) => any };
24
+ [ACTION_OWNER_META]: { [key: string]: ActionOwner };
23
25
  slice: { [key: string]: { [key: string]: SerializedSlice } };
24
26
  _slice: SliceInfoObj;
25
27
  }
@@ -0,0 +1,36 @@
1
+ import type { SerializedArg } from "akanjs/signal";
2
+ import type { SliceStateKey } from "./state";
3
+
4
+ /** The generated slice actions, named by what they do rather than by the key any one slice publishes them under. */
5
+ export type SliceActionKey =
6
+ | "initModel"
7
+ | "refreshModel"
8
+ | "selectModel"
9
+ | "setPageOfModel"
10
+ | "addPageOfModel"
11
+ | "setLimitOfModel"
12
+ | "setQueryArgsOfModel"
13
+ | "setSortOfModel";
14
+
15
+ /**
16
+ * What a generated key on `st.do` / `st.use` actually is.
17
+ *
18
+ * A slice publishes its keys with the model and the suffix spliced into the role name — `setPageOfUserInOrg` for the
19
+ * `setPageOfModel` role of `user`'s `inOrg` slice — and the splicing is string replacement over capitalized names.
20
+ * Recording the role while the key is being built is what saves a reader of the finished store from running that
21
+ * replacement backwards, which does not have one answer: on a model named `page`, `setPageOfPage` is both the
22
+ * paging action and a field setter.
23
+ */
24
+ export interface SliceActionRole {
25
+ role: SliceActionKey;
26
+ refName: string;
27
+ sliceName: string;
28
+ /** The slice's own arguments, which the `initModel` and `setQueryArgsOfModel` roles take positionally. */
29
+ args: SerializedArg[];
30
+ }
31
+
32
+ export interface SliceStateRole {
33
+ role: SliceStateKey;
34
+ refName: string;
35
+ sliceName: string;
36
+ }