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.
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/base/symbols.ts +4 -0
- package/client/clientRuntime.ts +8 -0
- package/client/cn.ts +7 -0
- package/client/csrTypes.ts +2 -0
- package/client/frameDebug.ts +3 -2
- package/common/Logger.ts +4 -0
- package/common/deepObjectify.ts +21 -7
- package/common/index.ts +14 -0
- package/common/mcpExposure.ts +99 -0
- package/common/pathSet.ts +17 -5
- package/common/routeConvention.ts +30 -0
- package/constant/crystalize.ts +3 -1
- package/constant/fieldInfo.ts +6 -0
- package/constant/getDefault.ts +37 -9
- package/constant/immerify.ts +1 -1
- package/constant/index.ts +2 -0
- package/constant/labelOf.ts +17 -0
- package/constant/mask.ts +60 -0
- package/constant/purify.ts +17 -11
- package/constant/types.ts +14 -12
- package/dictionary/DictionaryLookup.ts +30 -0
- package/dictionary/agent.dictionary.ts +31 -0
- package/dictionary/agentTurn.dictionary.ts +29 -0
- package/dictionary/base.dictionary.ts +8 -0
- package/dictionary/dictInfo.ts +8 -0
- package/dictionary/dictionary.ts +9 -3
- package/dictionary/index.ts +1 -0
- package/document/database.ts +21 -0
- package/document/filterMeta.ts +7 -0
- package/document/index.ts +1 -0
- package/document/into.ts +7 -1
- package/document/noDocumentError.ts +12 -0
- package/fetch/agentTurn.ts +19 -0
- package/fetch/client/fetchClient.ts +71 -13
- package/fetch/client/wsClient.ts +17 -2
- package/fetch/fetchType/endpointFetch.type.ts +10 -4
- package/fetch/index.ts +1 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db-wal +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-wal +0 -0
- package/package.json +11 -9
- package/server/akanApp.ts +30 -34
- package/server/akanOption.ts +65 -7
- package/server/akanServer.ts +172 -7
- package/server/animatedImage.ts +83 -0
- package/server/artifact/routeClientCache.ts +14 -0
- package/server/assetEncoding.ts +47 -0
- package/server/devtools/signalSerializer.ts +2 -2
- package/server/devtools/types.ts +2 -2
- package/server/di/diLifecycle.ts +31 -3
- package/server/di/predefinedAdaptor.ts +6 -0
- package/server/imageOptimizer.ts +33 -46
- package/server/index.ts +1 -2
- package/server/mcp/McpAuth.ts +177 -0
- package/server/mcp/McpDispatcher.ts +245 -0
- package/server/mcp/McpEventStream.ts +76 -0
- package/server/mcp/McpExecutionContext.ts +105 -0
- package/server/mcp/McpRouter.ts +591 -0
- package/server/mcp/index.ts +5 -0
- package/server/resolver/CascadeRunner.ts +1 -1
- package/server/resolver/database.resolver.ts +42 -5
- package/server/resolver/service.resolver.ts +29 -0
- package/server/resolver/signal.resolver.ts +16 -1
- package/server/routeTreeBuilder.ts +2 -44
- package/server/rscWorker.tsx +6 -2
- package/server/subRouteIndexDocument.tsx +61 -0
- package/server/systemPageDocument.tsx +2 -2
- package/server/systemPages.tsx +49 -16
- package/server/vendor/akanjs-fetch.ts +1 -0
- package/server/webRouter.ts +159 -35
- package/service/agent.service.ts +14 -0
- package/service/base.service.ts +2 -1
- package/service/index.ts +1 -0
- package/service/predefinedAdaptor/database.adaptor.ts +78 -24
- package/service/predefinedAdaptor/deepseekLlm.ts +230 -0
- package/service/predefinedAdaptor/index.ts +3 -0
- package/service/predefinedAdaptor/insightQuery.ts +183 -0
- package/service/predefinedAdaptor/llm.adaptor.ts +76 -0
- package/service/predefinedAdaptor/role.adaptor.ts +2 -0
- package/service/predefinedAdaptor/schedule.adaptor.ts +12 -5
- package/service/serviceModule.ts +17 -0
- package/service/types.ts +4 -0
- package/signal/agent/AgentCatalogue.ts +165 -0
- package/signal/agent/index.ts +1 -0
- package/signal/agent.signal.ts +42 -0
- package/signal/agentTurn.ts +8 -0
- package/signal/agentTurnStream.ts +48 -0
- package/signal/base.signal.ts +2 -1
- package/signal/endpointInfo.ts +38 -2
- package/signal/guard.ts +13 -1
- package/signal/guards.ts +52 -1
- package/signal/index.ts +6 -0
- package/signal/mcp/McpDocument.ts +286 -0
- package/signal/mcp/McpProgress.ts +106 -0
- package/signal/mcp/McpUriTemplate.ts +85 -0
- package/signal/mcp/Msg.ts +368 -0
- package/signal/mcp/index.ts +5 -0
- package/signal/mcp/mcpProtocol.ts +120 -0
- package/signal/middleware.ts +7 -3
- package/signal/openapi/openapi.ts +32 -171
- package/signal/schema/JsonSchemaBuilder.ts +211 -0
- package/signal/schema/index.ts +1 -0
- package/signal/signalContext.ts +85 -9
- package/signal/slice.ts +9 -9
- package/signal/types.ts +1 -1
- package/store/action.ts +11 -22
- package/store/actionTag.ts +33 -0
- package/store/agent/AgentBridge.ts +323 -0
- package/store/agent/AgentContext.ts +74 -0
- package/store/agent/AgentPrompts.ts +82 -0
- package/store/agent/AgentVisibility.ts +68 -0
- package/store/agent/ScreenReader.ts +208 -0
- package/store/agent/StoreCatalogue.ts +351 -0
- package/store/agent/StoreSurfaceSource.ts +122 -0
- package/store/agent/index.ts +9 -0
- package/store/agent/storeSurface.ts +28 -0
- package/store/agent/types.ts +50 -0
- package/store/agentic/StToolBuilder.ts +199 -0
- package/store/agentic/attachAgentic.ts +22 -0
- package/store/agentic/index.ts +5 -0
- package/store/agentic/readableValue.ts +17 -0
- package/store/agentic/useStExpose.ts +18 -0
- package/store/agentic/useStState.ts +35 -0
- package/store/baseSt.ts +7 -0
- package/store/databaseStateNames.ts +31 -0
- package/store/formSetterNames.ts +21 -0
- package/store/index.ts +8 -0
- package/store/rootStore.ts +3 -1
- package/store/sliceRole.ts +36 -0
- package/store/state.ts +2 -12
- package/store/store.ts +19 -1
- package/store/storeInstance.ts +165 -20
- package/store/storeRegistry.ts +16 -1
- package/store/types.ts +18 -0
- package/store/withSelector.ts +7 -8
- package/test/registerDom.ts +4 -0
- package/types/base/symbols.d.ts +4 -0
- package/types/client/cn.d.ts +5 -0
- package/types/client/csrTypes.d.ts +2 -0
- package/types/common/Logger.d.ts +2 -0
- package/types/common/deepObjectify.d.ts +4 -2
- package/types/common/index.d.ts +2 -1
- package/types/common/mcpExposure.d.ts +60 -0
- package/types/common/routeConvention.d.ts +8 -0
- package/types/constant/fieldInfo.d.ts +1 -0
- package/types/constant/getDefault.d.ts +5 -0
- package/types/constant/index.d.ts +2 -0
- package/types/constant/labelOf.d.ts +6 -0
- package/types/constant/mask.d.ts +34 -0
- package/types/constant/purify.d.ts +2 -2
- package/types/constant/types.d.ts +2 -2
- package/types/dictionary/DictionaryLookup.d.ts +14 -0
- package/types/dictionary/agent.dictionary.d.ts +1 -0
- package/types/dictionary/agentTurn.dictionary.d.ts +1 -0
- package/types/dictionary/base.dictionary.d.ts +1 -1
- package/types/dictionary/dictInfo.d.ts +6 -0
- package/types/dictionary/dictionary.d.ts +11 -9
- package/types/dictionary/index.d.ts +1 -0
- package/types/document/database.d.ts +20 -0
- package/types/document/filterMeta.d.ts +1 -0
- package/types/document/index.d.ts +1 -0
- package/types/document/into.d.ts +6 -1
- package/types/document/noDocumentError.d.ts +12 -0
- package/types/fetch/agentTurn.d.ts +593 -0
- package/types/fetch/client/fetchClient.d.ts +10 -0
- package/types/fetch/fetchType/endpointFetch.type.d.ts +5 -3
- package/types/fetch/index.d.ts +1 -0
- package/types/server/akanOption.d.ts +35 -7
- package/types/server/akanServer.d.ts +44 -1
- package/types/server/animatedImage.d.ts +7 -0
- package/types/server/artifact/routeClientCache.d.ts +6 -0
- package/types/server/assetEncoding.d.ts +7 -0
- package/types/server/devtools/types.d.ts +2 -2
- package/types/server/di/predefinedAdaptor.d.ts +4 -1
- package/types/server/index.d.ts +0 -2
- package/types/server/mcp/McpAuth.d.ts +62 -0
- package/types/server/mcp/McpDispatcher.d.ts +54 -0
- package/types/server/mcp/McpEventStream.d.ts +18 -0
- package/types/server/mcp/McpExecutionContext.d.ts +44 -0
- package/types/server/mcp/McpRouter.d.ts +60 -0
- package/types/server/mcp/index.d.ts +5 -0
- package/types/server/mcp.d.ts +1 -0
- package/types/server/subRouteIndexDocument.d.ts +8 -0
- package/types/server/systemPageDocument.d.ts +1 -0
- package/types/server/systemPages.d.ts +5 -0
- package/types/server/vendor/akanjs-fetch.d.ts +1 -0
- package/types/service/agent.service.d.ts +12 -0
- package/types/service/base.service.d.ts +4 -0
- package/types/service/index.d.ts +1 -0
- package/types/service/predefinedAdaptor/database.adaptor.d.ts +24 -2
- package/types/service/predefinedAdaptor/deepseekLlm.d.ts +64 -0
- package/types/service/predefinedAdaptor/index.d.ts +3 -0
- package/types/service/predefinedAdaptor/insightQuery.d.ts +50 -0
- package/types/service/predefinedAdaptor/llm.adaptor.d.ts +68 -0
- package/types/service/predefinedAdaptor/role.adaptor.d.ts +2 -0
- package/types/service/predefinedAdaptor/schedule.adaptor.d.ts +10 -6
- package/types/service/types.d.ts +4 -1
- package/types/signal/agent/AgentCatalogue.d.ts +100 -0
- package/types/signal/agent/index.d.ts +1 -0
- package/types/signal/agent.d.ts +1 -0
- package/types/signal/agent.signal.d.ts +29 -0
- package/types/signal/agentTurn.d.ts +9 -0
- package/types/signal/agentTurnStream.d.ts +16 -0
- package/types/signal/base.signal.d.ts +1 -1
- package/types/signal/endpointInfo.d.ts +21 -3
- package/types/signal/guard.d.ts +11 -0
- package/types/signal/guards.d.ts +22 -1
- package/types/signal/index.d.ts +6 -0
- package/types/signal/mcp/McpDocument.d.ts +65 -0
- package/types/signal/mcp/McpProgress.d.ts +40 -0
- package/types/signal/mcp/McpUriTemplate.d.ts +26 -0
- package/types/signal/mcp/Msg.d.ts +143 -0
- package/types/signal/mcp/index.d.ts +5 -0
- package/types/signal/mcp/mcpProtocol.d.ts +107 -0
- package/types/signal/mcp.d.ts +1 -0
- package/types/signal/openapi/openapi.d.ts +3 -3
- package/types/signal/schema/JsonSchemaBuilder.d.ts +47 -0
- package/types/signal/schema/index.d.ts +1 -0
- package/types/signal/schema.d.ts +1 -0
- package/types/signal/signalContext.d.ts +16 -1
- package/types/signal/slice.d.ts +8 -8
- package/types/signal/types.d.ts +1 -1
- package/types/store/actionTag.d.ts +21 -0
- package/types/store/agent/AgentBridge.d.ts +77 -0
- package/types/store/agent/AgentContext.d.ts +16 -0
- package/types/store/agent/AgentPrompts.d.ts +31 -0
- package/types/store/agent/AgentVisibility.d.ts +21 -0
- package/types/store/agent/ScreenReader.d.ts +11 -0
- package/types/store/agent/StoreCatalogue.d.ts +26 -0
- package/types/store/agent/StoreSurfaceSource.d.ts +18 -0
- package/types/store/agent/index.d.ts +9 -0
- package/types/store/agent/storeSurface.d.ts +14 -0
- package/types/store/agent/types.d.ts +49 -0
- package/types/store/agent.d.ts +1 -0
- package/types/store/agentic/StToolBuilder.d.ts +41 -0
- package/types/store/agentic/attachAgentic.d.ts +14 -0
- package/types/store/agentic/index.d.ts +5 -0
- package/types/store/agentic/readableValue.d.ts +3 -0
- package/types/store/agentic/useStExpose.d.ts +8 -0
- package/types/store/agentic/useStState.d.ts +12 -0
- package/types/store/agentic.d.ts +1 -0
- package/types/store/baseSt.d.ts +29 -22
- package/types/store/databaseStateNames.d.ts +25 -0
- package/types/store/formSetterNames.d.ts +16 -0
- package/types/store/index.d.ts +7 -0
- package/types/store/rootStore.d.ts +5 -1
- package/types/store/sliceRole.d.ts +25 -0
- package/types/store/store.d.ts +7 -2
- package/types/store/storeInstance.d.ts +33 -1
- package/types/store/storeRegistry.d.ts +5 -0
- package/types/store/types.d.ts +15 -0
- package/types/store/withSelector.d.ts +7 -8
- package/types/test/registerDom.d.ts +1 -0
- package/types/ui/Agent/Approval.d.ts +7 -0
- package/types/ui/Agent/Bubble.d.ts +13 -0
- package/types/ui/Agent/Chat.d.ts +24 -0
- package/types/ui/Agent/Context.d.ts +9 -0
- package/types/ui/Agent/Dock.d.ts +16 -0
- package/types/ui/Agent/Guide.d.ts +9 -0
- package/types/ui/Agent/Section.d.ts +10 -0
- package/types/ui/Agent/StateKey.d.ts +16 -0
- package/types/ui/Agent/Tool.d.ts +15 -0
- package/types/ui/Agent/Transcript.d.ts +13 -0
- package/types/ui/Agent/Zone.d.ts +23 -0
- package/types/ui/Agent/fetchRunner.d.ts +12 -0
- package/types/ui/Agent/index.d.ts +17 -0
- package/types/ui/Agent/index_.d.ts +1 -0
- package/types/ui/Agent/sessionHistory.d.ts +12 -0
- package/types/ui/Agent.d.ts +1 -0
- package/types/ui/Badge.d.ts +1 -1
- package/types/ui/Button.d.ts +1 -1
- package/types/ui/CsrImage.d.ts +1 -1
- package/types/ui/Dropdown.d.ts +2 -0
- package/types/ui/Image.d.ts +3 -3
- package/types/ui/Layout/BottomInset.d.ts +2 -1
- package/types/ui/Layout/index.d.ts +1 -1
- package/types/ui/Signal/style.d.ts +4 -1
- package/types/ui/UiOverride/context.d.ts +14 -2
- package/types/ui/agentAttrs.d.ts +14 -0
- package/types/ui/index.d.ts +4 -1
- package/types/ui/overlayLayer.d.ts +24 -0
- package/types/ui/recipe/badgeRecipe.d.ts +7 -3
- package/types/ui/recipe/buttonRecipe.d.ts +7 -3
- package/types/ui/recipe/inputRecipe.d.ts +5 -1
- package/types/vendor/use-agentic/AgentProvider.d.ts +18 -0
- package/types/vendor/use-agentic/AgentScope.d.ts +9 -0
- package/types/vendor/use-agentic/AgentSession.d.ts +50 -0
- package/types/vendor/use-agentic/Agentic.d.ts +21 -0
- package/types/vendor/use-agentic/AgenticSurface.d.ts +44 -0
- package/types/vendor/use-agentic/httpRunner.d.ts +15 -0
- package/types/vendor/use-agentic/index.d.ts +13 -0
- package/types/vendor/use-agentic/surfaceContext.d.ts +5 -0
- package/types/vendor/use-agentic/types.d.ts +133 -0
- package/types/vendor/use-agentic/useAgent.d.ts +4 -0
- package/types/vendor/use-agentic/useAgentGuide.d.ts +6 -0
- package/types/vendor/use-agentic/useAgentResource.d.ts +7 -0
- package/types/vendor/use-agentic/useAgentState.d.ts +13 -0
- package/types/vendor/use-agentic/useAgentTool.d.ts +16 -0
- package/types/vendor/use-agentic.d.ts +1 -0
- package/types/webkit/index.d.ts +3 -0
- package/types/webkit/lazy.d.ts +12 -0
- package/types/webkit/useCsrValues.d.ts +3 -3
- package/types/webkit/useEscapeKey.d.ts +5 -0
- package/types/webkit/useFrameRuntime.d.ts +6 -1
- package/types/webkit/useScreenScope.d.ts +18 -0
- package/ui/Agent/Approval.tsx +29 -0
- package/ui/Agent/Bubble.tsx +74 -0
- package/ui/Agent/Chat.tsx +225 -0
- package/ui/Agent/Context.tsx +38 -0
- package/ui/Agent/Dock.tsx +72 -0
- package/ui/Agent/Guide.tsx +16 -0
- package/ui/Agent/Section.tsx +24 -0
- package/ui/Agent/StateKey.tsx +44 -0
- package/ui/Agent/Tool.tsx +66 -0
- package/ui/Agent/Transcript.tsx +33 -0
- package/ui/Agent/Zone.tsx +48 -0
- package/ui/Agent/fetchRunner.ts +30 -0
- package/ui/Agent/index.ts +12 -0
- package/ui/Agent/index_.tsx +4 -0
- package/ui/Agent/sessionHistory.ts +33 -0
- package/ui/Badge.tsx +3 -3
- package/ui/BottomSheet.tsx +5 -0
- package/ui/Button.tsx +6 -2
- package/ui/Constant/Doc.tsx +1 -1
- package/ui/CsrImage.tsx +1 -1
- package/ui/Data/ListContainer.tsx +1 -1
- package/ui/DatePicker.tsx +5 -4
- package/ui/Dialog/Modal.tsx +12 -15
- package/ui/DraggableList.tsx +3 -1
- package/ui/Dropdown.tsx +33 -11
- package/ui/Field.tsx +30 -16
- package/ui/Image.tsx +3 -3
- package/ui/Input.tsx +14 -5
- package/ui/Layout/BottomInset.tsx +6 -1
- package/ui/Load/Units.tsx +11 -2
- package/ui/Load/View.tsx +7 -2
- package/ui/Loading/ProgressBar.tsx +8 -1
- package/ui/Menu.tsx +7 -8
- package/ui/Model/EditModal.tsx +37 -2
- package/ui/Model/SureToRemove.tsx +2 -1
- package/ui/Model/index_.tsx +42 -15
- package/ui/ObjectId.tsx +3 -4
- package/ui/Pagination.tsx +3 -4
- package/ui/Popconfirm.tsx +8 -7
- package/ui/Select.tsx +6 -4
- package/ui/Signal/RestApi.tsx +43 -16
- package/ui/Signal/WebSocket.tsx +1 -1
- package/ui/Signal/style.ts +6 -1
- package/ui/Switch.tsx +2 -0
- package/ui/System/CSR.tsx +6 -2
- package/ui/System/ThemeToggle.tsx +55 -33
- package/ui/ToggleSelect.tsx +4 -3
- package/ui/Tooltip.tsx +2 -1
- package/ui/UiOverride/context.ts +14 -2
- package/ui/agentAttrs.ts +19 -0
- package/ui/index.ts +10 -1
- package/ui/overlayLayer.ts +39 -0
- package/ui/recipe/badgeRecipe.ts +22 -3
- package/ui/recipe/buttonRecipe.ts +51 -2
- package/ui/recipe/factory.ts +2 -2
- package/ui/recipe/inputRecipe.ts +18 -4
- package/vendor/use-agentic/AgentProvider.tsx +39 -0
- package/vendor/use-agentic/AgentScope.tsx +20 -0
- package/vendor/use-agentic/AgentSession.ts +292 -0
- package/vendor/use-agentic/Agentic.tsx +44 -0
- package/vendor/use-agentic/AgenticSurface.ts +294 -0
- package/vendor/use-agentic/WIRE.md +57 -0
- package/vendor/use-agentic/httpRunner.ts +115 -0
- package/vendor/use-agentic/index.ts +14 -0
- package/vendor/use-agentic/surfaceContext.ts +9 -0
- package/vendor/use-agentic/types.ts +144 -0
- package/vendor/use-agentic/useAgent.ts +17 -0
- package/vendor/use-agentic/useAgentGuide.ts +16 -0
- package/vendor/use-agentic/useAgentResource.ts +30 -0
- package/vendor/use-agentic/useAgentState.ts +61 -0
- package/vendor/use-agentic/useAgentTool.ts +55 -0
- package/webkit/bootCsr.tsx +2 -33
- package/webkit/index.ts +3 -0
- package/webkit/lazy.tsx +27 -3
- package/webkit/useCsrValues.ts +121 -4
- package/webkit/useEscapeKey.tsx +42 -0
- package/webkit/useFrameRuntime.ts +65 -32
- package/webkit/useScreenScope.tsx +49 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { AgentContext } from "akanjs/store";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { AgenticSurface } from "../../vendor/use-agentic";
|
|
5
|
+
import { buttonRecipe } from "../recipe";
|
|
6
|
+
|
|
7
|
+
interface ContextProps {
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Assembles and shows the exact context blocks a turn would carry, on demand — the one preview of "what does the
|
|
13
|
+
* agent see on this screen" that no amount of reading the source answers.
|
|
14
|
+
*/
|
|
15
|
+
export default function Context({ className }: ContextProps) {
|
|
16
|
+
const [shown, setShown] = useState("");
|
|
17
|
+
const assemble = () => {
|
|
18
|
+
try {
|
|
19
|
+
const { guides } = AgenticSurface.shared.snapshot();
|
|
20
|
+
const context = AgentContext.of().blocks(AgenticSurface.shared);
|
|
21
|
+
setShown(JSON.stringify(guides.length ? { guides, context } : context, null, 2));
|
|
22
|
+
} catch (thrown) {
|
|
23
|
+
setShown(thrown instanceof Error ? thrown.message : String(thrown));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return (
|
|
27
|
+
<div className={className}>
|
|
28
|
+
<button className={buttonRecipe({ size: "xs" })} onClick={assemble} type="button">
|
|
29
|
+
Assemble
|
|
30
|
+
</button>
|
|
31
|
+
{shown ? (
|
|
32
|
+
<pre className="mt-2 max-h-60 overflow-auto rounded-field bg-base-100/60 p-2 text-[10px] leading-tight">
|
|
33
|
+
{shown}
|
|
34
|
+
</pre>
|
|
35
|
+
) : null}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
|
+
import { type AgentBridge, ensureStoreSurface, StoreRegistry } from "akanjs/store";
|
|
4
|
+
import { useRef, useState } from "react";
|
|
5
|
+
import Context from "./Context";
|
|
6
|
+
import Section from "./Section";
|
|
7
|
+
import StateKey from "./StateKey";
|
|
8
|
+
import Tool from "./Tool";
|
|
9
|
+
import Transcript from "./Transcript";
|
|
10
|
+
|
|
11
|
+
export interface DockProps {
|
|
12
|
+
className?: string;
|
|
13
|
+
/** Pass the bridge an agent is already driving so both write into one transcript. Defaults to the app's own. */
|
|
14
|
+
bridge?: AgentBridge;
|
|
15
|
+
open?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The in-page surface of the agent bridge: what this page lets an agent do, what it refused, and what it has done.
|
|
20
|
+
*
|
|
21
|
+
* It drives the store directly rather than talking to a model, because a model is not the framework's to choose —
|
|
22
|
+
* there is no provider or key here. An app wires its own agent to `bridge.tools` / `bridge.call` and can render this
|
|
23
|
+
* beside it; on its own it is the way to see the catalogue a page actually publishes, which is the one thing no
|
|
24
|
+
* amount of reading the source answers.
|
|
25
|
+
*/
|
|
26
|
+
export const Dock = ({ className, bridge, open = false }: DockProps) => {
|
|
27
|
+
const held = useRef<AgentBridge | null>(null);
|
|
28
|
+
held.current ??= bridge ?? ensureStoreSurface().bridge;
|
|
29
|
+
const agent = held.current;
|
|
30
|
+
const [ran, setRan] = useState(0);
|
|
31
|
+
const liveKeys = StoreRegistry.instance.liveKeys;
|
|
32
|
+
const stateEntries = Object.entries(agent.state).sort(([a], [b]) => {
|
|
33
|
+
const [liveA, liveB] = [liveKeys.has(a), liveKeys.has(b)];
|
|
34
|
+
if (liveA !== liveB) return liveA ? -1 : 1;
|
|
35
|
+
return a < b ? -1 : 1;
|
|
36
|
+
});
|
|
37
|
+
return (
|
|
38
|
+
<aside
|
|
39
|
+
data-agent-ui=""
|
|
40
|
+
className={cn(
|
|
41
|
+
"fixed right-4 bottom-4 z-50 flex max-h-[70vh] w-80 flex-col gap-2 overflow-y-auto rounded-box border border-base-content/10 bg-base-100/95 p-3 shadow-lg",
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
>
|
|
45
|
+
<h2 className="font-semibold text-sm">Agent</h2>
|
|
46
|
+
<Section count={agent.tools.length} open={open} title="Actions">
|
|
47
|
+
{agent.tools.map((tool) => (
|
|
48
|
+
<Tool bridge={agent} key={tool.name} onRun={() => setRan(ran + 1)} tool={tool} />
|
|
49
|
+
))}
|
|
50
|
+
</Section>
|
|
51
|
+
<Section count={Object.keys(agent.state).length} title="State">
|
|
52
|
+
{stateEntries.map(([name, entry]) => (
|
|
53
|
+
<StateKey bridge={agent} entry={entry} key={name} live={liveKeys.has(name)} name={name} />
|
|
54
|
+
))}
|
|
55
|
+
</Section>
|
|
56
|
+
<Section count={liveKeys.size} title="Context">
|
|
57
|
+
<Context />
|
|
58
|
+
</Section>
|
|
59
|
+
<Section count={agent.refusals.length} title="Refused">
|
|
60
|
+
{agent.refusals.map((refusal) => (
|
|
61
|
+
<div className="flex flex-col" key={refusal.key}>
|
|
62
|
+
<span className="truncate font-mono text-xs">{refusal.key}</span>
|
|
63
|
+
<span className="text-[10px] text-foreground/50">{refusal.reason}</span>
|
|
64
|
+
</div>
|
|
65
|
+
))}
|
|
66
|
+
</Section>
|
|
67
|
+
<Section count={agent.transcript.length} open title="Transcript">
|
|
68
|
+
<Transcript calls={agent.transcript} />
|
|
69
|
+
</Section>
|
|
70
|
+
</aside>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useAgentGuide } from "../../vendor/use-agentic";
|
|
3
|
+
|
|
4
|
+
export interface GuideProps {
|
|
5
|
+
instructions: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Standing agent guidance scoped to a route subtree: render it from a `_layout.tsx` or a page and the text joins
|
|
10
|
+
* the turn's instructions while that subtree is mounted. Nesting layers naturally — each mounted Guide contributes
|
|
11
|
+
* its block, and navigating away withdraws it. Renders nothing.
|
|
12
|
+
*/
|
|
13
|
+
export const Guide = ({ instructions }: GuideProps) => {
|
|
14
|
+
useAgentGuide(instructions);
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
interface SectionProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
title: string;
|
|
8
|
+
count: number;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
open?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default function Section({ className, title, count, children, open }: SectionProps) {
|
|
14
|
+
return (
|
|
15
|
+
<details className={cn("group rounded-box bg-muted", className)} open={open}>
|
|
16
|
+
<summary className="flex cursor-pointer list-none items-center gap-2 px-3 py-2 [&::-webkit-details-marker]:hidden">
|
|
17
|
+
<span className="font-semibold text-sm">{title}</span>
|
|
18
|
+
<span className="text-foreground/50 text-xs">{count}</span>
|
|
19
|
+
<span className="ml-auto text-foreground/40 transition-transform group-open:rotate-180">▾</span>
|
|
20
|
+
</summary>
|
|
21
|
+
<div className="flex flex-col gap-1 px-3 pb-3">{children}</div>
|
|
22
|
+
</details>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
|
+
import type { AgentBridge, SerializedStoreState } from "akanjs/store";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
|
|
6
|
+
interface StateKeyProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
bridge: AgentBridge;
|
|
9
|
+
name: string;
|
|
10
|
+
entry: SerializedStoreState;
|
|
11
|
+
live?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* One readable state key, read on demand rather than rendered with the rest.
|
|
16
|
+
*
|
|
17
|
+
* Reading is where masking happens, so a key that holds an object no model claims refuses here instead of in the
|
|
18
|
+
* catalogue — whether it is readable depends on what is in it, which the catalogue cannot know ahead of time.
|
|
19
|
+
*/
|
|
20
|
+
export default function StateKey({ className, bridge, name, entry, live }: StateKeyProps) {
|
|
21
|
+
const [shown, setShown] = useState("");
|
|
22
|
+
const read = () => {
|
|
23
|
+
try {
|
|
24
|
+
setShown(JSON.stringify(bridge.read(name), null, 2));
|
|
25
|
+
} catch (thrown) {
|
|
26
|
+
setShown(thrown instanceof Error ? thrown.message : String(thrown));
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return (
|
|
30
|
+
<div className={cn("flex flex-col gap-1", className)}>
|
|
31
|
+
<button className="flex items-center gap-2 text-left" type="button" onClick={read}>
|
|
32
|
+
<span className="truncate font-mono text-xs">{name}</span>
|
|
33
|
+
<span className="ml-auto shrink-0 text-[10px] text-foreground/40">
|
|
34
|
+
{live ? "live · " : ""}
|
|
35
|
+
{entry.refName ? `${entry.refName}.${entry.modelType ?? ""}` : entry.type}
|
|
36
|
+
{entry.derived ? " · derived" : ""}
|
|
37
|
+
</span>
|
|
38
|
+
</button>
|
|
39
|
+
{shown ? (
|
|
40
|
+
<pre className="max-h-40 overflow-auto rounded-field bg-muted p-2 text-[10px] leading-tight">{shown}</pre>
|
|
41
|
+
) : null}
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
|
+
import type { AgentBridge, AgentTool } from "akanjs/store";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { buttonRecipe } from "../recipe";
|
|
6
|
+
|
|
7
|
+
const effectClass: { [key in AgentTool["effect"]]: string } = {
|
|
8
|
+
state: "bg-muted text-foreground/70",
|
|
9
|
+
query: "bg-info/15 text-info",
|
|
10
|
+
mutation: "bg-warning/15 text-warning",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
interface ToolProps {
|
|
14
|
+
className?: string;
|
|
15
|
+
bridge: AgentBridge;
|
|
16
|
+
tool: AgentTool;
|
|
17
|
+
onRun: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One published action, with the arguments as JSON rather than as a generated form.
|
|
22
|
+
*
|
|
23
|
+
* A form per argument is what the API explorer does, and it is the wrong trade here: the point of the dock is to
|
|
24
|
+
* watch a call land in the running app, and every schema shape the store publishes is already legible as JSON.
|
|
25
|
+
*/
|
|
26
|
+
export default function Tool({ className, bridge, tool, onRun }: ToolProps) {
|
|
27
|
+
const [args, setArgs] = useState("{}");
|
|
28
|
+
const [error, setError] = useState("");
|
|
29
|
+
const run = async () => {
|
|
30
|
+
setError("");
|
|
31
|
+
try {
|
|
32
|
+
await bridge.call(tool.name, JSON.parse(args) as Record<string, unknown>);
|
|
33
|
+
} catch (thrown) {
|
|
34
|
+
setError(thrown instanceof Error ? thrown.message : String(thrown));
|
|
35
|
+
}
|
|
36
|
+
onRun();
|
|
37
|
+
};
|
|
38
|
+
return (
|
|
39
|
+
<details className={cn("rounded-field bg-base-100/60 px-2 py-1", className)}>
|
|
40
|
+
<summary className="flex cursor-pointer list-none items-center gap-2 [&::-webkit-details-marker]:hidden">
|
|
41
|
+
<span className={cn("rounded-field px-1.5 py-0.5 text-[10px] uppercase", effectClass[tool.effect])}>
|
|
42
|
+
{tool.effect}
|
|
43
|
+
</span>
|
|
44
|
+
<span className="truncate font-mono text-xs">{tool.name}</span>
|
|
45
|
+
</summary>
|
|
46
|
+
<div className="flex flex-col gap-2 py-2">
|
|
47
|
+
{tool.description ? <p className="text-foreground/70 text-xs">{tool.description}</p> : null}
|
|
48
|
+
<pre className="overflow-x-auto rounded-field bg-muted p-2 text-[10px] leading-tight">
|
|
49
|
+
{JSON.stringify(tool.inputSchema.properties, null, 2)}
|
|
50
|
+
</pre>
|
|
51
|
+
<textarea
|
|
52
|
+
className="w-full rounded-field bg-muted p-2 font-mono text-xs"
|
|
53
|
+
rows={2}
|
|
54
|
+
value={args}
|
|
55
|
+
onChange={(event) => setArgs(event.target.value)}
|
|
56
|
+
/>
|
|
57
|
+
{/* `buttonRecipe` rather than `Button`, which reads the app runtime through `usePage()` for labels this
|
|
58
|
+
developer surface does not localize anyway — the same English the API explorer uses. */}
|
|
59
|
+
<button className={buttonRecipe({ size: "xs" })} onClick={run} type="button">
|
|
60
|
+
Run
|
|
61
|
+
</button>
|
|
62
|
+
{error ? <p className="text-error text-xs">{error}</p> : null}
|
|
63
|
+
</div>
|
|
64
|
+
</details>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
|
+
import type { AgentCall } from "akanjs/store";
|
|
4
|
+
|
|
5
|
+
interface TranscriptProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
calls: readonly AgentCall[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* What the agent did, newest last, so the user can check it against what they saw the page do.
|
|
12
|
+
*
|
|
13
|
+
* There is no undo here. Every model removal in this framework is soft, so one is possible in principle, but which
|
|
14
|
+
* writes are reversible is a per-module judgement and `local/agent-native/PLAN.md` §9-3 leaves it open.
|
|
15
|
+
*/
|
|
16
|
+
export default function Transcript({ className, calls }: TranscriptProps) {
|
|
17
|
+
return (
|
|
18
|
+
<div className={cn("flex flex-col gap-1", className)}>
|
|
19
|
+
{calls.map((call, idx) => (
|
|
20
|
+
<div className="flex flex-col rounded-field bg-base-100/60 px-2 py-1" key={idx}>
|
|
21
|
+
<div className="flex items-baseline gap-2">
|
|
22
|
+
<span className="truncate font-mono text-xs">{call.name}</span>
|
|
23
|
+
<span className="ml-auto shrink-0 text-[10px] text-foreground/40">
|
|
24
|
+
{call.at.toISOString().slice(11, 19)}
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
<span className="truncate font-mono text-[10px] text-foreground/50">{JSON.stringify(call.args)}</span>
|
|
28
|
+
{call.error ? <span className="text-[10px] text-error">{call.error}</span> : null}
|
|
29
|
+
</div>
|
|
30
|
+
))}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { AgentContext, ensureStoreSurface } from "akanjs/store";
|
|
3
|
+
import { type ReactNode, useMemo, useRef } from "react";
|
|
4
|
+
import { AgenticSurface, type AgentRunner, AgentScope, AgentSession, SessionContext, useScopePath } from "../../vendor/use-agentic";
|
|
5
|
+
import { fetchRunner } from "./fetchRunner";
|
|
6
|
+
import { Guide } from "./Guide";
|
|
7
|
+
import { type PersistOption, sessionHistoryOf } from "./sessionHistory";
|
|
8
|
+
|
|
9
|
+
export interface ZoneProps {
|
|
10
|
+
className?: string;
|
|
11
|
+
/** Names the zone; the scope id and the `data-agent-zone` container both derive from it. */
|
|
12
|
+
id: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Zone-scoped guidance — a mounted Guide, so the root agent reads it too (ancestor rule), a sibling zone never does. */
|
|
15
|
+
instructions?: string;
|
|
16
|
+
runner?: AgentRunner;
|
|
17
|
+
maxTurns?: number;
|
|
18
|
+
/** Keeps this zone's transcript across reloads, keyed by the zone's scope path. */
|
|
19
|
+
persist?: PersistOption;
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A zone agent: one subtree with its own conversation over a scoped view of the same surface. Everything mounted
|
|
25
|
+
* inside — hook tools, `st.use` subscriptions, guides — belongs to this zone's session *and* to the root agent:
|
|
26
|
+
* zones are views, never walls. An `Agent.Chat` mounted inside binds to this session automatically, so two zones
|
|
27
|
+
* on one screen run two conversations in parallel, each seeing only its own subtree.
|
|
28
|
+
*/
|
|
29
|
+
export const Zone = ({ className, id, label, instructions, runner, maxTurns, persist, children }: ZoneProps) => {
|
|
30
|
+
const parent = useScopePath();
|
|
31
|
+
const path = useMemo(() => AgenticSurface.childPath(parent, id), [parent.join("."), id]);
|
|
32
|
+
const held = useRef<AgentSession | null>(null);
|
|
33
|
+
held.current ??= new AgentSession(ensureStoreSurface().surface.view(path), runner ?? fetchRunner(), {
|
|
34
|
+
buildContext: (view) => AgentContext.of().blocks(view, path),
|
|
35
|
+
...(maxTurns ? { maxTurns } : {}),
|
|
36
|
+
...(persist ? { history: sessionHistoryOf(persist, path.join(".")) } : {}),
|
|
37
|
+
});
|
|
38
|
+
return (
|
|
39
|
+
<AgentScope id={id} kind="zone" label={label}>
|
|
40
|
+
<SessionContext.Provider value={held.current}>
|
|
41
|
+
<div className={className} data-agent-zone={path.join(".")}>
|
|
42
|
+
{instructions ? <Guide instructions={instructions} /> : null}
|
|
43
|
+
{children}
|
|
44
|
+
</div>
|
|
45
|
+
</SessionContext.Provider>
|
|
46
|
+
</AgentScope>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getEnv } from "akanjs/base";
|
|
2
|
+
import { fetch } from "akanjs/client";
|
|
3
|
+
import { type AgentRunner, httpRunner } from "../../vendor/use-agentic";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Runs each assistant turn against the app's own `runAgentTurn` route — service signals mount unprefixed, so the
|
|
7
|
+
* URL is `<serverHttpUri>/runAgentTurn` — through the shared `httpRunner`, which negotiates streaming via
|
|
8
|
+
* `accept`: a server that streams answers SSE and the text arrives as it is generated; one that does not answers
|
|
9
|
+
* the same JSON turn. The client runtime's fetch proxy is only probed for whether the endpoint exists (the util
|
|
10
|
+
* lib ships one) and for the signed-in JWT; cookies ride the same-origin request on their own. The endpoint is a
|
|
11
|
+
* stateless relay; the loop and every tool execution stay in this browser session.
|
|
12
|
+
*/
|
|
13
|
+
export const fetchRunner = (options: { fetcher?: typeof globalThis.fetch } = {}): AgentRunner => ({
|
|
14
|
+
async *run(request) {
|
|
15
|
+
const client = fetch as { runAgentTurn?: unknown; instance?: { jwt?: string | null } };
|
|
16
|
+
if (typeof client.runAgentTurn !== "function") {
|
|
17
|
+
yield { type: "error", message: "No runAgentTurn endpoint is mounted on this app, so the agent cannot answer." };
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const runner = httpRunner({
|
|
21
|
+
url: `${getEnv().serverHttpUri}/runAgentTurn`,
|
|
22
|
+
headers: (): Record<string, string> => {
|
|
23
|
+
const jwt = client.instance?.jwt;
|
|
24
|
+
return jwt ? { authorization: `Bearer ${jwt}` } : {};
|
|
25
|
+
},
|
|
26
|
+
...(options.fetcher ? { fetcher: options.fetcher } : {}),
|
|
27
|
+
});
|
|
28
|
+
yield* runner.run(request);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AgentScope } from "../../vendor/use-agentic";
|
|
2
|
+
import Context from "./Context";
|
|
3
|
+
import { Dock } from "./Dock";
|
|
4
|
+
import { Guide } from "./Guide";
|
|
5
|
+
import { Chat } from "./index_";
|
|
6
|
+
import Section from "./Section";
|
|
7
|
+
import StateKey from "./StateKey";
|
|
8
|
+
import Tool from "./Tool";
|
|
9
|
+
import Transcript from "./Transcript";
|
|
10
|
+
import { Zone } from "./Zone";
|
|
11
|
+
|
|
12
|
+
export const Agent = { Chat, Context, Dock, Guide, Scope: AgentScope, Section, StateKey, Tool, Transcript, Zone };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getEnv } from "akanjs/base";
|
|
2
|
+
import type { ChatMessage, SessionHistory } from "../../vendor/use-agentic";
|
|
3
|
+
|
|
4
|
+
export type PersistOption = boolean | { storage?: "session" | "local"; key?: string };
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maps the `persist` prop onto a `SessionHistory` over web storage. Session storage is the default on purpose:
|
|
8
|
+
* surviving a refresh is the whole ask, and a transcript that dies with the tab never lingers on a shared machine
|
|
9
|
+
* or collides across tabs. `"local"` is the explicit opt-up. The envelope is versioned so a wire change discards
|
|
10
|
+
* stale transcripts instead of replaying them, and only the newest messages are kept under the cap.
|
|
11
|
+
*/
|
|
12
|
+
export const sessionHistoryOf = (persist: PersistOption | undefined, pathKey = ""): SessionHistory | undefined => {
|
|
13
|
+
if (!persist || typeof window === "undefined") return undefined;
|
|
14
|
+
const option = persist === true ? {} : persist;
|
|
15
|
+
const storage = option.storage === "local" ? window.localStorage : window.sessionStorage;
|
|
16
|
+
const key = option.key ?? `akan.agent.${getEnv().appName}${pathKey ? `.${pathKey}` : ""}`;
|
|
17
|
+
const version = 1;
|
|
18
|
+
const cap = 50;
|
|
19
|
+
return {
|
|
20
|
+
load: () => {
|
|
21
|
+
const raw = storage.getItem(key);
|
|
22
|
+
if (!raw) return null;
|
|
23
|
+
const parsed = JSON.parse(raw) as { v?: number; messages?: ChatMessage[] };
|
|
24
|
+
return parsed.v === version && Array.isArray(parsed.messages) ? parsed.messages : null;
|
|
25
|
+
},
|
|
26
|
+
save: (messages) => {
|
|
27
|
+
storage.setItem(key, JSON.stringify({ v: version, messages: messages.slice(-cap) }));
|
|
28
|
+
},
|
|
29
|
+
clear: () => {
|
|
30
|
+
storage.removeItem(key);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
};
|
package/ui/Badge.tsx
CHANGED
|
@@ -3,14 +3,14 @@ import type { HTMLAttributes } from "react";
|
|
|
3
3
|
import { type BadgeVariants, badgeRecipe } from "./recipe";
|
|
4
4
|
import { createOverridable, useUiRecipe } from "./UiOverride";
|
|
5
5
|
|
|
6
|
-
export {
|
|
6
|
+
export { type BadgeVariants, badgeRecipe };
|
|
7
7
|
|
|
8
8
|
export type BadgeProps = HTMLAttributes<HTMLSpanElement> & BadgeVariants;
|
|
9
9
|
|
|
10
|
-
const DefaultBadge = ({ className, variant, ...rest }: BadgeProps) => {
|
|
10
|
+
const DefaultBadge = ({ className, variant, size, outline, ...rest }: BadgeProps) => {
|
|
11
11
|
|
|
12
12
|
const recipe = useUiRecipe("badge") ?? badgeRecipe;
|
|
13
|
-
return <span className={recipe({ variant }, className)} {...rest} />;
|
|
13
|
+
return <span className={recipe({ variant, size, outline }, className)} {...rest} />;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
/** Status/label pill. Route-overridable via `page/**\/_overrides.tsx` (slot `Badge`). */
|
package/ui/BottomSheet.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { useDrag } from "@use-gesture/react";
|
|
|
3
3
|
import { cn } from "akanjs/client";
|
|
4
4
|
import { st } from "akanjs/store";
|
|
5
5
|
import { animated } from "akanjs/ui";
|
|
6
|
+
import { useEscapeKey } from "akanjs/webkit";
|
|
6
7
|
import { forwardRef, type ReactNode, useEffect, useImperativeHandle, useRef } from "react";
|
|
7
8
|
import { BiX } from "react-icons/bi";
|
|
8
9
|
import { config, useSpring } from "react-spring";
|
|
@@ -54,6 +55,10 @@ export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
|
|
|
54
55
|
close: closeModal,
|
|
55
56
|
}));
|
|
56
57
|
|
|
58
|
+
useEscapeKey(open, () => {
|
|
59
|
+
void closeModal();
|
|
60
|
+
});
|
|
61
|
+
|
|
57
62
|
useEffect(() => {
|
|
58
63
|
if (open) void openModal();
|
|
59
64
|
else void closeModal();
|
package/ui/Button.tsx
CHANGED
|
@@ -4,10 +4,11 @@ import { isThenable } from "akanjs/common";
|
|
|
4
4
|
import type React from "react";
|
|
5
5
|
import { type ButtonHTMLAttributes, type ComponentType, createElement, useState } from "react";
|
|
6
6
|
import { AiFillCheckCircle, AiOutlineLoading3Quarters } from "react-icons/ai";
|
|
7
|
+
import { agentAttrs } from "./agentAttrs";
|
|
7
8
|
import { type ButtonVariants, buttonRecipe } from "./recipe";
|
|
8
9
|
import { useUiOverride, useUiRecipe } from "./UiOverride";
|
|
9
10
|
|
|
10
|
-
export {
|
|
11
|
+
export { type ButtonVariants, buttonRecipe };
|
|
11
12
|
|
|
12
13
|
export type ButtonProps<Result> = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onClick"> &
|
|
13
14
|
ButtonVariants & {
|
|
@@ -61,6 +62,8 @@ const DefaultButton = <Result = unknown>({
|
|
|
61
62
|
className,
|
|
62
63
|
variant,
|
|
63
64
|
size,
|
|
65
|
+
shape,
|
|
66
|
+
outline,
|
|
64
67
|
type = "button",
|
|
65
68
|
loadingMode = "hold",
|
|
66
69
|
showError = true,
|
|
@@ -84,11 +87,12 @@ const DefaultButton = <Result = unknown>({
|
|
|
84
87
|
<button
|
|
85
88
|
type={type}
|
|
86
89
|
className={recipe(
|
|
87
|
-
{ variant, size },
|
|
90
|
+
{ variant, size, shape, outline },
|
|
88
91
|
|
|
89
92
|
cn(loadingMode === "hold" && "relative", busy && !rest.disabled && "disabled:opacity-100", className),
|
|
90
93
|
)}
|
|
91
94
|
{...rest}
|
|
95
|
+
{...agentAttrs(onClick)}
|
|
92
96
|
disabled={!!rest.disabled || busy}
|
|
93
97
|
onClick={(e) => {
|
|
94
98
|
if (!onClick) return;
|
package/ui/Constant/Doc.tsx
CHANGED
|
@@ -238,7 +238,7 @@ const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
|
|
|
238
238
|
const { l } = usePage();
|
|
239
239
|
return (
|
|
240
240
|
<div className="overflow-x-auto rounded-xl bg-muted p-3">
|
|
241
|
-
<table className=
|
|
241
|
+
<table className={tableClass}>
|
|
242
242
|
<thead>
|
|
243
243
|
<tr>
|
|
244
244
|
<th>Key</th>
|
package/ui/CsrImage.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import type { ImgHTMLAttributes } from "react";
|
|
|
5
5
|
type CsrImageProps = Omit<ImgHTMLAttributes<HTMLImageElement>, "alt" | "src"> & {
|
|
6
6
|
src?: string;
|
|
7
7
|
file?: ProtoFile | { url: string; imageSize: [number, number]; abstractData?: string | null } | null;
|
|
8
|
-
abstractData?: string;
|
|
8
|
+
abstractData?: string | null;
|
|
9
9
|
priority?: boolean;
|
|
10
10
|
preload?: boolean;
|
|
11
11
|
quality?: number;
|
|
@@ -268,7 +268,7 @@ export default function ListContainer<
|
|
|
268
268
|
<div className={cn("m-4", className)}>
|
|
269
269
|
<div className="mb-3 flex flex-wrap justify-between">
|
|
270
270
|
<div className="flex pb-1">
|
|
271
|
-
<p className="
|
|
271
|
+
<p className="text-lg">
|
|
272
272
|
{title ?? l._(`${sliceName}.modelName`)}({modelInsight.count})
|
|
273
273
|
</p>
|
|
274
274
|
<div className="ml-3 flex items-center">
|
package/ui/DatePicker.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { lazy } from "akanjs/webkit";
|
|
|
5
5
|
import { type FocusEvent, useEffect, useRef } from "react";
|
|
6
6
|
import { AiOutlineSwapRight } from "react-icons/ai";
|
|
7
7
|
|
|
8
|
+
import { inputRecipe } from "./recipe";
|
|
8
9
|
import { createOverridable } from "./UiOverride";
|
|
9
10
|
|
|
10
11
|
const reactDatePickerPackage = "react-datepicker";
|
|
@@ -58,7 +59,7 @@ const DefaultDatePicker = ({
|
|
|
58
59
|
|
|
59
60
|
return (
|
|
60
61
|
<ReactDatePicker
|
|
61
|
-
className={
|
|
62
|
+
className={inputRecipe({}, ["text-center", className])}
|
|
62
63
|
selected={value ? value.toDate() : new Date()}
|
|
63
64
|
disabledKeyboardNavigation
|
|
64
65
|
onFocus={(e: FocusEvent<HTMLInputElement>) => {
|
|
@@ -110,9 +111,9 @@ const DefaultRangePicker = ({
|
|
|
110
111
|
onChange([value[0] ?? dayjs(), dayjs(date)]);
|
|
111
112
|
};
|
|
112
113
|
|
|
113
|
-
const pickerClassName = "m-0
|
|
114
|
+
const pickerClassName = "m-0 h-full w-full border-none bg-transparent p-3 text-center focus:outline-hidden z-50";
|
|
114
115
|
return (
|
|
115
|
-
<div className={
|
|
116
|
+
<div className={inputRecipe({}, ["flex h-full w-fit items-center gap-2 p-0", className])}>
|
|
116
117
|
<ReactDatePicker
|
|
117
118
|
className={pickerClassName}
|
|
118
119
|
selected={value[0] ? value[0].toDate() : undefined}
|
|
@@ -136,7 +137,7 @@ const DefaultRangePicker = ({
|
|
|
136
137
|
showTimeSelect={showTime}
|
|
137
138
|
timeIntervals={timeIntervals}
|
|
138
139
|
filterDate={(date: Date) =>
|
|
139
|
-
!disabledDate?.(dayjs(date)) &&
|
|
140
|
+
!disabledDate?.(dayjs(date)) && value[0] && !dayjs(date).add(1, "day").isBefore(value[0]) ? true : false
|
|
140
141
|
}
|
|
141
142
|
filterTime={(time: Date) => !!value[0] && dayjs(time).isAfter(value[0])}
|
|
142
143
|
dateFormat={format}
|
package/ui/Dialog/Modal.tsx
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
import { useDrag } from "@use-gesture/react";
|
|
3
3
|
import { cn, usePage } from "akanjs/client";
|
|
4
4
|
import { animated } from "akanjs/ui";
|
|
5
|
+
import { useEscapeKey } from "akanjs/webkit";
|
|
5
6
|
import { type ReactNode, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
|
|
6
7
|
import { createPortal } from "react-dom";
|
|
7
8
|
import { BiX } from "react-icons/bi";
|
|
8
9
|
import { config, useSpring } from "react-spring";
|
|
9
10
|
import { buttonRecipe } from "../Button";
|
|
11
|
+
import { useOverlayLayerProps } from "../overlayLayer";
|
|
10
12
|
|
|
11
13
|
import { DialogContext } from "./context";
|
|
12
14
|
|
|
@@ -35,6 +37,8 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
35
37
|
const focusedElementRef = useRef<HTMLElement | null>(null);
|
|
36
38
|
const titleId = useId();
|
|
37
39
|
const contentId = useId();
|
|
40
|
+
|
|
41
|
+
const overlayLayerProps = useOverlayLayerProps();
|
|
38
42
|
const [{ translate }, api] = useSpring(() => ({ translate: 1 }));
|
|
39
43
|
const [portalElement, setPortalElement] = useState<HTMLElement | null>(null);
|
|
40
44
|
const [isMounted, setIsMounted] = useState(open);
|
|
@@ -160,20 +164,7 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
160
164
|
};
|
|
161
165
|
}, [isMounted, portalElement]);
|
|
162
166
|
|
|
163
|
-
|
|
164
|
-
if (!isMounted) return;
|
|
165
|
-
|
|
166
|
-
const onKeyDown = (event: KeyboardEvent) => {
|
|
167
|
-
if (event.key !== "Escape") return;
|
|
168
|
-
event.preventDefault();
|
|
169
|
-
requestClose();
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
window.addEventListener("keydown", onKeyDown);
|
|
173
|
-
return () => {
|
|
174
|
-
window.removeEventListener("keydown", onKeyDown);
|
|
175
|
-
};
|
|
176
|
-
}, [isMounted, requestClose]);
|
|
167
|
+
useEscapeKey(isMounted, requestClose);
|
|
177
168
|
|
|
178
169
|
useEffect(() => {
|
|
179
170
|
return () => {
|
|
@@ -186,17 +177,23 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
186
177
|
return createPortal(
|
|
187
178
|
<>
|
|
188
179
|
<div
|
|
180
|
+
{...overlayLayerProps}
|
|
189
181
|
className={cn("fixed inset-0 z-10", showBackground && "animate-fadeIn bg-black/50 backdrop-blur-md")}
|
|
190
182
|
onClick={(event) => {
|
|
191
183
|
if (event.target !== event.currentTarget) return;
|
|
192
184
|
requestClose();
|
|
193
185
|
}}
|
|
194
186
|
/>
|
|
195
|
-
<div
|
|
187
|
+
<div
|
|
188
|
+
{...overlayLayerProps}
|
|
189
|
+
className="fixed top-1/2 left-1/2 z-10 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center"
|
|
190
|
+
>
|
|
196
191
|
<div className="z-10">
|
|
197
192
|
<animated.div
|
|
198
193
|
ref={ref}
|
|
199
194
|
style={{ translateY, opacity }}
|
|
195
|
+
|
|
196
|
+
className="outline-none"
|
|
200
197
|
role="dialog"
|
|
201
198
|
aria-modal="true"
|
|
202
199
|
aria-labelledby={title ? titleId : undefined}
|