From c57deffd52d27482dc09120e6b9c4d9573a883b3 Mon Sep 17 00:00:00 2001 From: xiayu Date: Tue, 21 Jul 2026 17:40:30 +0800 Subject: [PATCH 01/61] fix(web): stabilize session history switching --- src/App.tsx | 12 +- src/__tests__/api-facade.test.ts | 58 +++++- .../chat-message-list-contract.test.ts | 25 ++- src/__tests__/composer-contract.test.ts | 1 + src/__tests__/messages-mapper.test.ts | 15 ++ src/__tests__/run-engine.test.ts | 10 +- .../session-message-history-store.test.ts | 50 +++++ src/api/messages.ts | 8 +- src/components/chat/ConnectedMessageList.tsx | 43 +++- src/core/api/facade.ts | 11 +- src/core/api/types.ts | 3 +- src/core/run/engine.ts | 8 +- src/hooks/useSessionLifecycle.ts | 195 ++++++++++-------- src/stores/session.ts | 53 +++-- src/utils/messages.js | 10 +- src/utils/session-message-history.ts | 9 + 16 files changed, 356 insertions(+), 155 deletions(-) create mode 100644 src/__tests__/session-message-history-store.test.ts create mode 100644 src/utils/session-message-history.ts diff --git a/src/App.tsx b/src/App.tsx index 1ebb8d3..1d37ebe 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -99,7 +99,7 @@ export function AgentWorkbench({ apiAdapter, initialSurface = 'chat', routeShell fetchSessions, loadMoreSessions, loadSession, - loadOlderSessionEvents, + loadOlderSessionMessages, createNewSession, deleteSession, currentSessionIdRef, @@ -121,7 +121,7 @@ export function AgentWorkbench({ apiAdapter, initialSurface = 'chat', routeShell return; } const refresh = () => { - useSessionStore.getState().clearSessionEventCache(sessionId); + useSessionStore.getState().clearSessionMessageHistory(sessionId); void fetchSessions(agentIdRef.current, sessionId); }; queueMicrotask(refresh); @@ -166,10 +166,10 @@ export function AgentWorkbench({ apiAdapter, initialSurface = 'chat', routeShell const handleCancelRemote = useCallback(async () => { const sessionId = currentSessionIdRef.current; const streamingState = useStreamingStore.getState(); - const invocationId = streamingState.currentRunId || streamingState.getSessionActivity(sessionId)?.runId || ''; - if (invocationId) { + const invocationId = streamingState.getSessionActivity(sessionId)?.runId || streamingState.currentRunId || ''; + if (sessionId && invocationId) { try { - await api.cancelRun(agentId, invocationId); + await api.cancelRun(agentId, sessionId, invocationId); useStreamingStore.getState().stopSessionActivity( sessionId, '取消请求已发送,后台运行会停在最近 checkpoint。', @@ -366,7 +366,7 @@ export function AgentWorkbench({ apiAdapter, initialSurface = 'chat', routeShell uiCapabilities.RunLifecycle.CheckpointResume } onResumeCheckpoint={resumeCheckpoint} - onLoadOlderSessionEvents={loadOlderSessionEvents} + onLoadOlderSessionMessages={loadOlderSessionMessages} /> { const facade = new ApiFacadeImpl(); const methods: (keyof ApiFacade)[] = [ 'listSessions', 'createSession', 'deleteSession', 'getSession', - 'listSessionEvents', 'listSessionMessages', 'listSessionCheckpoints', 'listToolReceipts', 'previewCheckpointResume', 'runAgent', 'resumeRun', 'subscribeRunEvents', + 'listSessionEvents', 'listSessionMessages', 'listSessionCheckpoints', 'listToolReceipts', 'previewCheckpointResume', 'runAgent', 'resumeRun', 'subscribeRunEvents', 'cancelRun', 'getResponseFeedback', 'upsertResponseFeedback', 'deleteResponseFeedback', 'listWorkspaceFiles', 'addWorkspaceFile', 'deleteWorkspaceFile', 'getWorkspaceFileContent', 'listAgentModels', 'getAgentUiBootstrap', 'uploadFile', @@ -149,6 +149,62 @@ describe('ApiFacadeImpl', () => { ]); }); + it('uses message cursors for older history and scopes cancellation to the session', async () => { + const facade = new ApiFacadeImpl(); + const calls: Array<{ url: string; body: Record }> = []; + const originalFetch = globalThis.fetch; + + globalThis.fetch = (async (url, init) => { + calls.push({ + url: String(url), + body: JSON.parse(String(init?.body || '{}')) as Record, + }); + const data = String(url).endsWith('/ListSessionMessages') + ? { Messages: [{ MessageId: 'evt-2', Role: 'assistant', SeqId: 2 }], LatestSeqId: 2, HasMore: false, NextCursor: null } + : { Cancelled: true }; + return new Response(JSON.stringify({ Code: 0, Data: data }), { + status: 200, + headers: { 'content-type': 'application/json' }, + }); + }) as typeof fetch; + + try { + const messagePage = await facade.listSessionMessages('session-1', { + beforeSeqId: 6, + limit: 50, + includeReasoning: true, + includeToolEvents: true, + includeAttachments: true, + }); + expect(messagePage.NextCursor).toBeNull(); + await facade.cancelRun('agent-1', 'session-1', 'run-1'); + } finally { + globalThis.fetch = originalFetch; + } + + expect(calls).toEqual([ + { + url: '/agentengine/api/v1/ListSessionMessages', + body: { + SessionId: 'session-1', + BeforeSeqId: 6, + Limit: 50, + IncludeReasoning: true, + IncludeToolEvents: true, + IncludeAttachments: true, + }, + }, + { + url: '/agentengine/api/v1/CancelRun', + body: { + AgentId: 'agent-1', + SessionId: 'session-1', + InvocationId: 'run-1', + }, + }, + ]); + }); + it('maps checkpoint actions to backend action payloads', async () => { const facade = new ApiFacadeImpl(); const calls: Array<{ url: string; body: Record }> = []; diff --git a/src/__tests__/chat-message-list-contract.test.ts b/src/__tests__/chat-message-list-contract.test.ts index bc39422..afaf540 100644 --- a/src/__tests__/chat-message-list-contract.test.ts +++ b/src/__tests__/chat-message-list-contract.test.ts @@ -130,13 +130,13 @@ describe('chat message list contracts', () => { expect(listSource).toContain('取消运行并保留最近 checkpoint'); }); - it('loads checkpoint metadata as best effort without blocking session history', () => { + it('uses projected message cursors without duplicating raw event history loads', () => { const lifecycleSource = readFileSync(resolve(repoRoot, 'src/hooks/useSessionLifecycle.ts'), 'utf8'); - expect(lifecycleSource).toContain('loadCompleteSessionEventHistory'); - expect(lifecycleSource).toContain('SESSION_EVENTS_RESTORE_PAGE_SIZE'); - expect(lifecycleSource).toContain('loadOlderSessionEvents'); - expect(lifecycleSource).not.toContain('Promise.all([\\n api.listSessionEvents(sessionId)'); + expect(lifecycleSource).toContain('loadOlderSessionMessages'); + expect(lifecycleSource).toContain('beforeSeqId: historyState.nextCursor'); + expect(lifecycleSource).toContain('SESSION_MESSAGES_PAGE_SIZE'); + expect(lifecycleSource).not.toContain('api.listSessionEvents(sessionId'); expect(lifecycleSource).toContain("console.warn('[SessionLifecycle] checkpoint load failed:'"); expect(lifecycleSource).toContain("console.warn('[SessionLifecycle] tool receipt load failed:'"); }); @@ -168,13 +168,24 @@ describe('chat message list contracts', () => { expect(lifecycleSource).toContain('status: terminalActivity.status'); }); + it('does not let a stale detached subscription clear the active run', () => { + const lifecycleSource = readFileSync(resolve(repoRoot, 'src/hooks/useSessionLifecycle.ts'), 'utf8'); + + expect(lifecycleSource).toContain('const isCurrentSubscription = () =>'); + expect(lifecycleSource).toContain('runSubscriptionAbortRef.current === controller'); + expect(lifecycleSource).toContain('const ownedCurrentSubscription ='); + expect(lifecycleSource).toContain('if (ownedCurrentSubscription && currentSessionIdRef.current === options.sessionId)'); + expect(lifecycleSource).not.toContain('let mergedEvents: SessionEventRecord[]'); + }); + it('does not let stale session history overwrite the active transcript', () => { const appSource = readFileSync(resolve(repoRoot, 'src/App.tsx'), 'utf8'); const lifecycleSource = readFileSync(resolve(repoRoot, 'src/hooks/useSessionLifecycle.ts'), 'utf8'); expect(appSource).not.toContain('void loadSession(sessionId);'); - expect(appSource).toContain('clearSessionEventCache(sessionId)'); - expect(lifecycleSource).toContain('const isStillCurrentSession = () => currentSessionIdRef.current === sessionId;'); + expect(appSource).toContain('clearSessionMessageHistory(sessionId)'); + expect(lifecycleSource).toContain('const isStillCurrentSession = () => ('); + expect(lifecycleSource).toContain('loadSessionGenerationRef.current === generation'); expect(lifecycleSource).toContain('if (!isStillCurrentSession()) {'); expect(lifecycleSource).toContain('currentSessionIdRef.current === options.sessionId'); // PR4:重连期间不覆盖消息列表(保持 loadSession 的 ListSessionMessages 结果), diff --git a/src/__tests__/composer-contract.test.ts b/src/__tests__/composer-contract.test.ts index bacf688..86486f8 100644 --- a/src/__tests__/composer-contract.test.ts +++ b/src/__tests__/composer-contract.test.ts @@ -36,6 +36,7 @@ describe('ChatComposer interaction contract', () => { const cancelHandler = source.slice(cancelHandlerStart, cancelHandlerEnd); expect(cancelHandler).toContain('const sessionId = currentSessionIdRef.current'); + expect(cancelHandler).toContain('api.cancelRun(agentId, sessionId, invocationId)'); expect(cancelHandler).toContain('refreshSettledRun(sessionId)'); expect(cancelHandler).toContain('取消请求已发送'); expect(cancelHandler).toMatch(/stopSessionActivity\(\s*sessionId/); diff --git a/src/__tests__/messages-mapper.test.ts b/src/__tests__/messages-mapper.test.ts index c7d4df7..08f327b 100644 --- a/src/__tests__/messages-mapper.test.ts +++ b/src/__tests__/messages-mapper.test.ts @@ -48,6 +48,21 @@ describe('mapBackendMessage', () => { expect(result.tools.search.status).toBe('completed'); }); + it('keeps same-name tool calls distinct by ToolCallId', () => { + const result = mapBackendMessage({ + Role: 'assistant', + Content: { text: 'done' }, + ToolEvents: [ + { Name: 'search', ToolCallId: 'call-1', Args: { q: 'one' }, Result: 'first' }, + { Name: 'search', ToolCallId: 'call-2', Args: { q: 'two' }, Result: 'second' }, + ], + } satisfies BackendMessage); + + expect(Object.keys(result.tools)).toEqual(['call-1', 'call-2']); + expect(result.tools['call-1'].args).toBe('{"q":"one"}'); + expect(result.tools['call-2'].output).toBe('second'); + }); + it('maps paused approval tool event', () => { const msg: BackendMessage = { Role: 'assistant', diff --git a/src/__tests__/run-engine.test.ts b/src/__tests__/run-engine.test.ts index c0a72ed..ef9fd02 100644 --- a/src/__tests__/run-engine.test.ts +++ b/src/__tests__/run-engine.test.ts @@ -46,8 +46,8 @@ function createApiFacade(calls: Record[], uploadCalls: FormData async subscribeRunEvents() { return new ReadableStream(); }, - async cancelRun(agentId, invocationId) { - calls.push({ cancel: { agentId, invocationId } }); + async cancelRun(agentId, sessionId, invocationId) { + calls.push({ cancel: { agentId, sessionId, invocationId } }); return { Cancelled: true, Found: true, Status: 'cancelling' }; }, async getResponseFeedback() { return null; }, @@ -369,7 +369,7 @@ describe('RunEngineImpl', () => { await engine.cancelRemote(invocationId); expect(calls.at(-1)).toEqual({ - cancel: { agentId: 'agent-live', invocationId }, + cancel: { agentId: 'agent-live', sessionId: 'session-live', invocationId }, }); }); @@ -626,7 +626,7 @@ describe('RunEngineImpl', () => { await waitForCalls(calls, 2); expect(calls.at(-1)).toEqual({ - cancel: { agentId: 'agent-live', invocationId }, + cancel: { agentId: 'agent-live', sessionId: 'session-live', invocationId }, }); }); @@ -841,7 +841,7 @@ describe('RunEngineImpl', () => { await engine.cancelRemote(invocationId); expect(calls.at(-1)).toEqual({ - cancel: { agentId: 'agent-live', invocationId }, + cancel: { agentId: 'agent-live', sessionId: 'session-live', invocationId }, }); }); }); diff --git a/src/__tests__/session-message-history-store.test.ts b/src/__tests__/session-message-history-store.test.ts new file mode 100644 index 0000000..83450b1 --- /dev/null +++ b/src/__tests__/session-message-history-store.test.ts @@ -0,0 +1,50 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { useSessionStore } from '../stores/session.js'; +import { ownsOlderMessageScrollRequest } from '../utils/session-message-history.js'; + +describe('session message history state', () => { + afterEach(() => { + useSessionStore.getState().clearSessionMessageHistory(); + }); + + it('keeps independent cursors per session and clears only the requested session', () => { + const store = useSessionStore.getState(); + store.setSessionMessageHistory('session-a', { nextCursor: 8, hasMore: true }); + store.setSessionMessageHistory('session-b', { nextCursor: null, hasMore: false }); + store.setSessionMessageHistoryLoading('session-a', true); + + expect(useSessionStore.getState().messageHistory).toEqual({ + 'session-a': { nextCursor: 8, hasMore: true, isLoadingOlder: true }, + 'session-b': { nextCursor: null, hasMore: false, isLoadingOlder: false }, + }); + + store.clearSessionMessageHistory('session-a'); + + expect(useSessionStore.getState().messageHistory).toEqual({ + 'session-b': { nextCursor: null, hasMore: false, isLoadingOlder: false }, + }); + }); + + it('rejects stale older-message scroll work after session or request changes', () => { + const requestToken = Symbol('request-a'); + + expect(ownsOlderMessageScrollRequest({ + requestedSessionId: 'session-a', + activeSessionId: 'session-a', + requestToken, + activeRequestToken: requestToken, + })).toBe(true); + expect(ownsOlderMessageScrollRequest({ + requestedSessionId: 'session-a', + activeSessionId: 'session-b', + requestToken, + activeRequestToken: requestToken, + })).toBe(false); + expect(ownsOlderMessageScrollRequest({ + requestedSessionId: 'session-a', + activeSessionId: 'session-a', + requestToken, + activeRequestToken: Symbol('replacement'), + })).toBe(false); + }); +}); diff --git a/src/api/messages.ts b/src/api/messages.ts index b1b510a..bb8e5f6 100644 --- a/src/api/messages.ts +++ b/src/api/messages.ts @@ -33,6 +33,7 @@ export type BackendMessage = { export type ListSessionMessagesOptions = { agentId?: string; afterSeqId?: number; + beforeSeqId?: number; limit?: number; includeReasoning?: boolean; includeToolEvents?: boolean; @@ -57,6 +58,7 @@ export async function listSessionMessages( AgentId: opts?.agentId, SessionId: sessionId, AfterSeqId: opts?.afterSeqId, + BeforeSeqId: opts?.beforeSeqId, Limit: opts?.limit, IncludeReasoning: opts?.includeReasoning, IncludeToolEvents: opts?.includeToolEvents, @@ -68,6 +70,10 @@ export async function listSessionMessages( Messages: data.Messages ?? [], LatestSeqId: Number.isFinite(Number(data.LatestSeqId)) ? Number(data.LatestSeqId) : 0, HasMore: Boolean(data.HasMore), - NextCursor: Number.isFinite(Number(data.NextCursor)) ? Number(data.NextCursor) : null, + NextCursor: data.NextCursor === null || data.NextCursor === undefined + ? null + : Number.isFinite(Number(data.NextCursor)) + ? Number(data.NextCursor) + : null, }; } diff --git a/src/components/chat/ConnectedMessageList.tsx b/src/components/chat/ConnectedMessageList.tsx index c5d0700..d3deca3 100644 --- a/src/components/chat/ConnectedMessageList.tsx +++ b/src/components/chat/ConnectedMessageList.tsx @@ -8,6 +8,7 @@ import { useCheckpointStore } from '../../stores/checkpoint.js'; import { ChatMessageList } from './ChatMessageList'; import { AttachmentPreview } from './AttachmentPreview'; import { buildComposerContextIndicator } from '../../utils/context.js'; +import { ownsOlderMessageScrollRequest } from '../../utils/session-message-history.js'; import type { ComposerContextIndicator, Message, MessageAttachment } from './types'; import type { ModelStore } from '../../stores/model.js'; import type { SessionStore } from '../../stores/session.js'; @@ -24,7 +25,7 @@ type ConnectedMessageListProps = { onCancelRemote?: () => void; checkpointResumeEnabled?: boolean; onResumeCheckpoint?: (params: { sessionId: string; runId: string; checkpointId: string }) => void; - onLoadOlderSessionEvents?: (sessionId: string) => Promise; + onLoadOlderSessionMessages?: (sessionId: string) => Promise; }; export function ConnectedMessageList({ @@ -37,15 +38,15 @@ export function ConnectedMessageList({ onCancelRemote, checkpointResumeEnabled = false, onResumeCheckpoint, - onLoadOlderSessionEvents, + onLoadOlderSessionMessages, }: ConnectedMessageListProps) { const messages = useMessageStore(s => s.messages); const currentSessionId = useSessionStore((s: SessionStore) => s.currentSessionId); const isStreaming = useStreamingStore((s: StreamingStore) => Boolean(s.getSessionActivity(currentSessionId) && s.isSessionStreaming(currentSessionId))); const activity = useStreamingStore((s: StreamingStore) => s.getSessionActivity(currentSessionId)); const checkpoints = useCheckpointStore(s => s.getSessionCheckpoints(currentSessionId)); - const currentEventCache = useSessionStore((s: SessionStore) => - currentSessionId ? s.eventCache[currentSessionId] : null, + const currentMessageHistory = useSessionStore((s: SessionStore) => + currentSessionId ? s.messageHistory[currentSessionId] : null, ); const input = useUIStore((s: UIStore) => s.input); const availableModels = useModelStore((s: ModelStore) => s.availableModels); @@ -58,6 +59,7 @@ export function ConnectedMessageList({ const previousScrollTopRef = useRef(0); const isStreamingRef = useRef(isStreaming); const loadingOlderRef = useRef(false); + const olderLoadTokenRef = useRef(null); const needsInitialScrollRef = useRef(true); const selectedModelMetadata = useMemo( () => availableModels.find((model) => model.id === selectedModel) || null, @@ -87,6 +89,8 @@ export function ConnectedMessageList({ stickToBottomRef.current = true; userDetachedFromBottomRef.current = false; previousScrollTopRef.current = 0; + loadingOlderRef.current = false; + olderLoadTokenRef.current = null; }, [currentSessionId]); useEffect(() => { @@ -102,17 +106,31 @@ export function ConnectedMessageList({ if ( scroller.scrollTop < 200 && currentSessionId && - currentEventCache && - currentEventCache.offset > 0 && - !currentEventCache.isLoadingOlder && + currentMessageHistory?.hasMore && + !currentMessageHistory.isLoadingOlder && !loadingOlderRef.current && - onLoadOlderSessionEvents + onLoadOlderSessionMessages ) { const previousScrollHeight = scroller.scrollHeight; + const requestedSessionId = currentSessionId; + const requestToken = Symbol(requestedSessionId); loadingOlderRef.current = true; - void onLoadOlderSessionEvents(currentSessionId) + olderLoadTokenRef.current = requestToken; + void onLoadOlderSessionMessages(requestedSessionId) .then(() => { + if (!ownsOlderMessageScrollRequest({ + requestedSessionId, + activeSessionId: useSessionStore.getState().currentSessionId, + requestToken, + activeRequestToken: olderLoadTokenRef.current, + })) return; requestAnimationFrame(() => { + if (!ownsOlderMessageScrollRequest({ + requestedSessionId, + activeSessionId: useSessionStore.getState().currentSessionId, + requestToken, + activeRequestToken: olderLoadTokenRef.current, + })) return; const nextScroller = scrollRef.current; if (!nextScroller) return; const delta = nextScroller.scrollHeight - previousScrollHeight; @@ -121,7 +139,10 @@ export function ConnectedMessageList({ }); }) .finally(() => { - loadingOlderRef.current = false; + if (olderLoadTokenRef.current === requestToken) { + olderLoadTokenRef.current = null; + loadingOlderRef.current = false; + } }); } @@ -144,7 +165,7 @@ export function ConnectedMessageList({ updateStickiness(); scroller.addEventListener('scroll', updateStickiness, { passive: true }); return () => scroller.removeEventListener('scroll', updateStickiness); - }, [currentEventCache, currentSessionId, onLoadOlderSessionEvents]); + }, [currentMessageHistory, currentSessionId, onLoadOlderSessionMessages]); useEffect(() => { const scroller = scrollRef.current; diff --git a/src/core/api/facade.ts b/src/core/api/facade.ts index 5db2e7f..57aed5c 100644 --- a/src/core/api/facade.ts +++ b/src/core/api/facade.ts @@ -39,6 +39,7 @@ export class ApiFacadeImpl implements ApiFacade { opts?: { agentId?: string; afterSeqId?: number; + beforeSeqId?: number; limit?: number; includeReasoning?: boolean; includeToolEvents?: boolean; @@ -75,7 +76,7 @@ export class ApiFacadeImpl implements ApiFacade { } async resumeRun( - params: { agentId: string; sessionId: string; runId: string; checkpointId: string; resumeAttemptId?: string }, + params: { agentId: string; sessionId: string; runId: string; checkpointId: string; resumeAttemptId?: string; invocationId?: string }, opts?: { signal?: AbortSignal }, ) { return resumeRunApi(params, opts); @@ -93,8 +94,12 @@ export class ApiFacadeImpl implements ApiFacade { return streamGetAction('SubscribeRunEvents', qs, opts); } - async cancelRun(agentId: string, invocationId: string, opts?: { signal?: AbortSignal }) { - return postJsonAction('CancelRun', { AgentId: agentId, InvocationId: invocationId }, opts); + async cancelRun(agentId: string, sessionId: string, invocationId: string, opts?: { signal?: AbortSignal }) { + return postJsonAction( + 'CancelRun', + { AgentId: agentId, SessionId: sessionId, InvocationId: invocationId }, + opts, + ); } // Feedback diff --git a/src/core/api/types.ts b/src/core/api/types.ts index 676ba31..2f36fde 100644 --- a/src/core/api/types.ts +++ b/src/core/api/types.ts @@ -38,6 +38,7 @@ export interface ApiFacade { opts?: { agentId?: string; afterSeqId?: number; + beforeSeqId?: number; limit?: number; includeReasoning?: boolean; includeToolEvents?: boolean; @@ -56,7 +57,7 @@ export interface ApiFacade { runAgent(body: Record, opts?: { signal?: AbortSignal }): Promise>; resumeRun(params: { agentId: string; sessionId: string; runId: string; checkpointId: string; resumeAttemptId?: string; invocationId?: string }, opts?: { signal?: AbortSignal }): Promise>; subscribeRunEvents(params: { sessionId: string; invocationId: string; afterSeqId: number }, opts?: { signal?: AbortSignal }): Promise>; - cancelRun(agentId: string, invocationId: string, opts?: { signal?: AbortSignal }): Promise; + cancelRun(agentId: string, sessionId: string, invocationId: string, opts?: { signal?: AbortSignal }): Promise; // Feedback getResponseFeedback(payload: Record, opts?: { signal?: AbortSignal }): Promise; diff --git a/src/core/run/engine.ts b/src/core/run/engine.ts index f7c2e91..d28f8e7 100644 --- a/src/core/run/engine.ts +++ b/src/core/run/engine.ts @@ -272,8 +272,8 @@ export class RunEngineImpl implements RunEngine { if (this._stage === 'idle') return; this.setStage('stopping'); const invocationId = useStreamingStore.getState().currentRunId; - if (invocationId) { - void this.api.cancelRun(this.config.agentId, invocationId).catch((err) => { + if (invocationId && this.activeSessionId) { + void this.api.cancelRun(this.config.agentId, this.activeSessionId, invocationId).catch((err) => { console.warn('[RunEngine] cancelRun on stop failed:', err); }); } @@ -305,7 +305,9 @@ export class RunEngineImpl implements RunEngine { async cancelRemote(invocationId: string): Promise { try { - await this.api.cancelRun(this.config.agentId, invocationId); + if (this.activeSessionId) { + await this.api.cancelRun(this.config.agentId, this.activeSessionId, invocationId); + } } catch (err) { console.warn('[RunEngine] cancelRemote failed:', err); } diff --git a/src/hooks/useSessionLifecycle.ts b/src/hooks/useSessionLifecycle.ts index 5375d85..b1bac02 100644 --- a/src/hooks/useSessionLifecycle.ts +++ b/src/hooks/useSessionLifecycle.ts @@ -6,19 +6,13 @@ import { useCheckpointStore } from '../stores/checkpoint.js'; import { useBootstrapStore } from '../stores/bootstrap.js'; import { CancelledError } from '../api/client.js'; import { - buildMessagesFromSessionEvents, eventHasTerminalRunStatus, - mergeSessionEventRecords, } from '../utils/session-events.js'; import { mapBackendMessages } from '../utils/messages.js'; import { useStreamingStore } from '../stores/streaming.js'; import { shouldRenderFeedbackControls, normalizeFeedback } from '../utils/feedback.js'; import { readPersistedSessionId, resolveSessionToRestore } from '../utils/session.js'; import { resolveNextSessionsPage } from '../utils/session-pagination.js'; -import { - loadCompleteSessionEventHistory, - resolveOlderSessionEventPage, -} from '../utils/session-event-history.js'; import type { Message, Session } from '../components/chat/types.js'; import type { SessionEventRecord } from '../types/session-events.js'; import type { UiCapabilities } from '../types/capabilities.js'; @@ -26,8 +20,7 @@ import type { ApiFacade } from '../core/api/types.js'; const RESTORE_SUBSCRIPTION_TIMEOUT_MS = 90_000; const SESSION_LIST_PAGE_SIZE = 30; -const SESSION_EVENTS_PAGE_SIZE = 50; -const SESSION_EVENTS_RESTORE_PAGE_SIZE = 500; +const SESSION_MESSAGES_PAGE_SIZE = 50; // 重连判据:ActiveRunStatus 属于这些态时认为有活跃 run(对齐后端 RUN_STATUS_ACTIVE)。 const ACTIVE_RUN_STATUSES = new Set([ @@ -37,16 +30,6 @@ const ACTIVE_RUN_STATUSES = new Set([ 'starting', ]); -function historyShouldReplaceMessages(history: Message[], currentMessages: Message[]) { - if (!currentMessages.length) { - return true; - } - if (!history.length) { - return false; - } - return history.length >= currentMessages.length; -} - function terminalActivityForRunEvent(event: SessionEventRecord): { status: 'completed' | 'failed' | 'stopped'; phase: string; @@ -93,6 +76,8 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { const currentSessionIdRef = useRef(ctx.currentSessionId); const agentIdRef = useRef(ctx.agentId); const runSubscriptionAbortRef = useRef(null); + const loadSessionGenerationRef = useRef(0); + const olderMessageRequestRef = useRef(new Map()); const loadSessionRef = useRef<((sessionId: string) => Promise) | null>(null); const fetchSessionsRef = useRef< (( @@ -161,13 +146,16 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { sessionId: string; invocationId: string; afterSeqId: number; - initialEvents?: SessionEventRecord[]; }) => { runSubscriptionAbortRef.current?.abort(); const controller = new AbortController(); runSubscriptionAbortRef.current = controller; let shouldReloadSession = false; let terminalStatusSeen = false; + const isCurrentSubscription = () => ( + runSubscriptionAbortRef.current === controller + && currentSessionIdRef.current === options.sessionId + ); const stopRestoreSubscription = () => { if (runSubscriptionAbortRef.current !== controller || controller.signal.aborted) { return; @@ -187,12 +175,13 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { }, { signal: controller.signal }, ); + if (!isCurrentSubscription()) { + controller.abort(); + return; + } const reader = stream.getReader(); const decoder = new TextDecoder(); let buffer = ''; - let mergedEvents: SessionEventRecord[] = Array.isArray(options.initialEvents) - ? options.initialEvents - : []; useStreamingStore.getState().setCurrentRunId(options.invocationId); useStreamingStore.getState().updateActivity({ sessionId: options.sessionId, @@ -225,7 +214,10 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { } try { const event = JSON.parse(dataString) as SessionEventRecord; - mergedEvents = mergeSessionEventRecords(mergedEvents, [event]) as SessionEventRecord[]; + if (!isCurrentSubscription()) { + stopRestoreSubscription(); + break; + } terminalStatusSeen = terminalStatusSeen || eventHasTerminalRunStatus(event); shouldReloadSession = shouldReloadSession || terminalStatusSeen; if (event.EventType === 'run_checkpoint') { @@ -241,10 +233,6 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { countEvent: false, }); } - if (currentSessionIdRef.current !== options.sessionId) { - stopRestoreSubscription(); - break; - } // 重连期间不覆盖消息列表(保持 loadSession 的 ListSessionMessages 结果)。 // run 结束后 shouldReloadSession 会重新 loadSession 拿最终消息。 // 增量事件仅更新 streaming activity(上方 terminalActivity 已处理)。 @@ -260,14 +248,17 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { } } finally { globalThis.clearTimeout(timeoutTimer); - if (runSubscriptionAbortRef.current === controller) { + const ownedCurrentSubscription = runSubscriptionAbortRef.current === controller; + if (ownedCurrentSubscription) { runSubscriptionAbortRef.current = null; } - useStreamingStore.getState().setCurrentRunId(''); - if (shouldReloadSession && currentSessionIdRef.current === options.sessionId) { - void loadSessionRef.current?.(options.sessionId); + if (ownedCurrentSubscription && currentSessionIdRef.current === options.sessionId) { + useStreamingStore.getState().setCurrentRunId(''); + if (shouldReloadSession) { + void loadSessionRef.current?.(options.sessionId); + } + void fetchSessionsRef.current?.(agentIdRef.current, options.sessionId); } - void fetchSessionsRef.current?.(agentIdRef.current, options.sessionId); } }, [api], @@ -275,8 +266,23 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { const loadSession = useCallback( async (sessionId: string) => { + const previousSessionId = currentSessionIdRef.current; + const generation = ++loadSessionGenerationRef.current; + if (previousSessionId !== sessionId) { + disconnectRun?.(); + useMessageStore.getState().setMessages([]); + useSessionStore.getState().clearSessionMessageHistory(sessionId); + useCheckpointStore.getState().setSessionCheckpoints(sessionId, []); + useCheckpointStore.getState().setSessionToolReceipts(sessionId, []); + useStreamingStore.getState().setCurrentRunId(''); + useStreamingStore.getState().clearActivity(); + useStreamingStore.getState().clearSessionActivity(previousSessionId); + } currentSessionIdRef.current = sessionId; - const isStillCurrentSession = () => currentSessionIdRef.current === sessionId; + const isStillCurrentSession = () => ( + currentSessionIdRef.current === sessionId + && loadSessionGenerationRef.current === generation + ); useSessionStore.getState().setCurrentSessionId(sessionId); resetCompaction(); runSubscriptionAbortRef.current?.abort(); @@ -285,13 +291,8 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { } try { - // PR4:用 ListSessionMessages 替换 buildMessagesFromSessionEvents(服务端投影)。 - // 同时仍拉 ListSessionEvents 填 eventCache(供 loadOlderSessionEvents 向上翻页, - // 后端 ListSessionMessages 的 BeforeSeqId 留作后续优化)。 - // 注意:不传 agentId —— hosted-ui 会话历史存在 server DB,走 hosted path - // (ConversationService.get_events + 投影)。传 agentId 会触发 runtime path - // (从 runtime agent 拉事件),hosted 场景 runtime 不持有会话历史 → 消息消失。 const messagesData = await api.listSessionMessages(sessionId, { + limit: SESSION_MESSAGES_PAGE_SIZE, includeReasoning: true, includeToolEvents: true, includeAttachments: true, @@ -301,37 +302,25 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { } const history = mapBackendMessages(messagesData.Messages); useMessageStore.getState().setMessages(history); + useSessionStore.getState().setSessionMessageHistory(sessionId, { + nextCursor: messagesData.NextCursor, + hasMore: messagesData.HasMore, + }); void loadFeedbackForMessages(agentIdRef.current, sessionId, history); const lastSeqId = messagesData.LatestSeqId || 0; - // 填 eventCache(供 loadOlderSessionEvents 翻更早历史;非阻塞) - // offset 表示"已加载多少条最新事件",首次拿 limit=500 条后 offset=已加载数量, - // 否则 loadOlder 会重复从 offset=0 拉最新页。 - void api.listSessionEvents(sessionId, { limit: SESSION_EVENTS_RESTORE_PAGE_SIZE }) - .then((eventData) => { - if (!isStillCurrentSession()) return; - const loadedEvents = (eventData.Events || []) as SessionEventRecord[]; - useSessionStore.getState().setSessionEventCache(sessionId, { - events: loadedEvents, - total: eventData.Total ?? 0, - offset: (eventData.Offset ?? 0) + loadedEvents.length, - limit: eventData.Limit ?? 0, - }); - }) - .catch((error) => { - console.warn('[SessionLifecycle] event cache load failed:', error); - }); - const runtimeCapabilities = useBootstrapStore.getState().capabilities || uiCapabilities; if (runtimeCapabilities.RunLifecycle.Enabled && runtimeCapabilities.RunLifecycle.Checkpoints) { void api.listSessionCheckpoints({ agentId: agentIdRef.current, sessionId, }).then((checkpointData) => { + if (!isStillCurrentSession()) return; useCheckpointStore .getState() .setSessionCheckpoints(sessionId, checkpointData.Checkpoints || []); }).catch((error) => { + if (!isStillCurrentSession()) return; console.warn('[SessionLifecycle] checkpoint load failed:', error); useCheckpointStore.getState().setSessionCheckpoints(sessionId, []); }); @@ -339,10 +328,12 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { agentId: agentIdRef.current, sessionId, }).then((receiptData) => { + if (!isStillCurrentSession()) return; useCheckpointStore .getState() .setSessionToolReceipts(sessionId, receiptData.ToolReceipts || []); }).catch((error) => { + if (!isStillCurrentSession()) return; console.warn('[SessionLifecycle] tool receipt load failed:', error); useCheckpointStore.getState().setSessionToolReceipts(sessionId, []); }); @@ -367,7 +358,6 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { sessionId, invocationId: session.ActiveInvocationId!, afterSeqId: lastSeqId, - initialEvents: [], }); } } catch (error) { @@ -380,6 +370,7 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { }, [ api, + disconnectRun, isMobile, loadFeedbackForMessages, resetCompaction, @@ -419,10 +410,16 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { if (restoredSessionId && restoredSessionId !== activeSessionId) { void loadSession(restoredSessionId); } else if (!restoredSessionId && activeSessionId) { + loadSessionGenerationRef.current += 1; + runSubscriptionAbortRef.current?.abort(); + disconnectRun?.(); currentSessionIdRef.current = null; useSessionStore.getState().setCurrentSessionId(null); useMessageStore.getState().setMessages([]); + useSessionStore.getState().clearSessionMessageHistory(); useCheckpointStore.getState().clearSessionCheckpoints(); + useStreamingStore.getState().setCurrentRunId(''); + useStreamingStore.getState().clearActivity(); } } catch (error) { if (error instanceof CancelledError) return; @@ -431,7 +428,7 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { useSessionStore.getState().setLoadingSessions(false); } }, - [api, loadSession], + [api, disconnectRun, loadSession], ); const loadMoreSessions = useCallback(async () => { @@ -480,6 +477,8 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { const createNewSession = useCallback(async () => { try { disconnectRun?.(); + loadSessionGenerationRef.current += 1; + runSubscriptionAbortRef.current?.abort(); const session = await api.createSession(agentId); const newId = session.SessionId; if (newId) { @@ -489,8 +488,11 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { currentSessionIdRef.current = newId; useSessionStore.getState().setCurrentSessionId(newId); useMessageStore.getState().setMessages([]); + useSessionStore.getState().clearSessionMessageHistory(newId); useCheckpointStore.getState().setSessionCheckpoints(newId, []); useCheckpointStore.getState().setSessionToolReceipts(newId, []); + useStreamingStore.getState().setCurrentRunId(''); + useStreamingStore.getState().clearActivity(); if (isMobile) { useUIStore.getState().setMobileSidebarOpen(false); useUIStore.getState().setMobileActionsOpen(false); @@ -508,12 +510,17 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { try { await api.deleteSession(sessionId); useSessionStore.getState().removeSession(sessionId); - useSessionStore.getState().clearSessionEventCache(sessionId); + useSessionStore.getState().clearSessionMessageHistory(sessionId); if (currentSessionIdRef.current === sessionId) { + loadSessionGenerationRef.current += 1; + runSubscriptionAbortRef.current?.abort(); + disconnectRun?.(); currentSessionIdRef.current = null; useMessageStore.getState().setMessages([]); useCheckpointStore.getState().clearSessionCheckpoints(sessionId); useSessionStore.getState().setCurrentSessionId(null); + useStreamingStore.getState().setCurrentRunId(''); + useStreamingStore.getState().clearActivity(); void fetchSessions(agentId); } } catch (error) { @@ -521,41 +528,59 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { console.error('Failed to delete session', error); } }, - [agentId, api, fetchSessions], + [agentId, api, disconnectRun, fetchSessions], ); - const loadOlderSessionEvents = useCallback(async (sessionId: string) => { - const cache = useSessionStore.getState().eventCache[sessionId]; - if (!cache || cache.isLoadingOlder) { - return; - } - const nextPage = resolveOlderSessionEventPage(cache, SESSION_EVENTS_PAGE_SIZE); - if (!nextPage) { + const loadOlderSessionMessages = useCallback(async (sessionId: string) => { + const historyState = useSessionStore.getState().messageHistory[sessionId]; + if ( + !historyState + || !historyState.hasMore + || historyState.nextCursor === null + || historyState.isLoadingOlder + ) { return; } + const generation = loadSessionGenerationRef.current; + const requestToken = Symbol(sessionId); + olderMessageRequestRef.current.set(sessionId, requestToken); try { - useSessionStore.getState().setSessionEventLoadingOlder(sessionId, true); - const data = await api.listSessionEvents(sessionId, nextPage); - const incoming = (data.Events || []) as SessionEventRecord[]; - const merged = mergeSessionEventRecords(incoming, cache.events) as SessionEventRecord[]; - const loadedCount = cache.offset + incoming.length; - useSessionStore.getState().setSessionEventCache(sessionId, { - events: merged, - total: Number(data.Total ?? cache.total), - offset: loadedCount, - limit: merged.length, + useSessionStore.getState().setSessionMessageHistoryLoading(sessionId, true); + const data = await api.listSessionMessages(sessionId, { + beforeSeqId: historyState.nextCursor, + limit: SESSION_MESSAGES_PAGE_SIZE, + includeReasoning: true, + includeToolEvents: true, + includeAttachments: true, }); - if (currentSessionIdRef.current === sessionId) { - const history = buildMessagesFromSessionEvents(merged); - useMessageStore.getState().setMessages(history); - void loadFeedbackForMessages(agentIdRef.current, sessionId, history); + if ( + currentSessionIdRef.current !== sessionId + || loadSessionGenerationRef.current !== generation + || olderMessageRequestRef.current.get(sessionId) !== requestToken + ) { + return; } + const olderMessages = mapBackendMessages(data.Messages); + const olderIds = new Set(olderMessages.map((message) => message.id)); + const mergedHistory = [ + ...olderMessages, + ...useMessageStore.getState().messages.filter((message) => !olderIds.has(message.id)), + ]; + useMessageStore.getState().setMessages(mergedHistory); + useSessionStore.getState().setSessionMessageHistory(sessionId, { + nextCursor: data.NextCursor, + hasMore: data.HasMore, + }); + void loadFeedbackForMessages(agentIdRef.current, sessionId, olderMessages); } catch (error) { if (!(error instanceof CancelledError)) { - console.error('Failed to load older session events:', error); + console.error('Failed to load older session messages:', error); } } finally { - useSessionStore.getState().setSessionEventLoadingOlder(sessionId, false); + if (olderMessageRequestRef.current.get(sessionId) === requestToken) { + olderMessageRequestRef.current.delete(sessionId); + useSessionStore.getState().setSessionMessageHistoryLoading(sessionId, false); + } } }, [api, loadFeedbackForMessages]); @@ -563,7 +588,7 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { fetchSessions, loadMoreSessions, loadSession, - loadOlderSessionEvents, + loadOlderSessionMessages, createNewSession, deleteSession, currentSessionIdRef, diff --git a/src/stores/session.ts b/src/stores/session.ts index ef7743a..b1b0086 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -1,6 +1,5 @@ import { create } from 'zustand'; import type { Session } from '../components/chat/types.js'; -import type { SessionEventRecord } from '../types/session-events.js'; import { buildSessionPaginationState, mergeLoadedPages } from '../utils/session-pagination.js'; export type SessionState = { @@ -14,11 +13,9 @@ export type SessionState = { hasMoreSessions: boolean; isLoadingSessions: boolean; pinnedSessionIds: string[]; - eventCache: Record; }; @@ -37,15 +34,13 @@ export type SessionActions = { setLoadingSessions: (loading: boolean) => void; resetSessionPagination: (agentId: string) => void; togglePinnedSession: (id: string) => void; - setSessionEventCache: (sessionId: string, cache: { - events: SessionEventRecord[]; - total: number; - offset: number; - limit: number; + setSessionMessageHistory: (sessionId: string, history: { + nextCursor: number | null; + hasMore: boolean; isLoadingOlder?: boolean; }) => void; - setSessionEventLoadingOlder: (sessionId: string, loading: boolean) => void; - clearSessionEventCache: (sessionId?: string) => void; + setSessionMessageHistoryLoading: (sessionId: string, loading: boolean) => void; + clearSessionMessageHistory: (sessionId?: string) => void; }; function sessionUpdatedAtValue(session: Session): number { @@ -118,7 +113,7 @@ export const useSessionStore = create()((set) => ({ hasMoreSessions: false, isLoadingSessions: false, pinnedSessionIds: readPinnedSessionIds(), - eventCache: {}, + messageHistory: {}, setSessions: (sessions) => set((s) => ({ sessions: sortSessions(sessions, s.pinnedSessionIds) })), setCurrentSessionId: (id) => set({ currentSessionId: id }), @@ -193,37 +188,35 @@ export const useSessionStore = create()((set) => ({ sessions: sortSessions(s.sessions, pinnedSessionIds), }; }), - setSessionEventCache: (sessionId, cache) => + setSessionMessageHistory: (sessionId, history) => set((s) => ({ - eventCache: { - ...s.eventCache, + messageHistory: { + ...s.messageHistory, [sessionId]: { - events: cache.events, - total: cache.total, - offset: cache.offset, - limit: cache.limit, - isLoadingOlder: cache.isLoadingOlder ?? false, + nextCursor: history.nextCursor, + hasMore: history.hasMore, + isLoadingOlder: history.isLoadingOlder ?? false, }, }, })), - setSessionEventLoadingOlder: (sessionId, loading) => + setSessionMessageHistoryLoading: (sessionId, loading) => set((s) => { - const existing = s.eventCache[sessionId]; + const existing = s.messageHistory[sessionId]; if (!existing) return {}; return { - eventCache: { - ...s.eventCache, + messageHistory: { + ...s.messageHistory, [sessionId]: { ...existing, isLoadingOlder: loading }, }, }; }), - clearSessionEventCache: (sessionId) => + clearSessionMessageHistory: (sessionId) => set((s) => { if (!sessionId) { - return { eventCache: {} }; + return { messageHistory: {} }; } - const next = { ...s.eventCache }; + const next = { ...s.messageHistory }; delete next[sessionId]; - return { eventCache: next }; + return { messageHistory: next }; }), })); diff --git a/src/utils/messages.js b/src/utils/messages.js index 024df78..d8743bb 100644 --- a/src/utils/messages.js +++ b/src/utils/messages.js @@ -39,6 +39,11 @@ function extractContentText(content) { function mapToolEvents(toolEvents) { const tools = {}; + const nameCounts = new Map(); + for (const te of toolEvents ?? []) { + if (!te?.Name) continue; + nameCounts.set(te.Name, (nameCounts.get(te.Name) || 0) + 1); + } for (const te of toolEvents ?? []) { if (!te?.Name) continue; const status = TOOL_STATUS_MAP[String(te.Status ?? 'completed').toLowerCase()] ?? 'completed'; @@ -57,8 +62,9 @@ function mapToolEvents(toolEvents) { if (te.ToolCallId) { entry.previousResponseId = te.ToolCallId; } - // 同名 tool 后者覆盖前者(保留最后状态) - tools[te.Name] = entry; + // 仅同名多次时用 ToolCallId 分键;单工具和旧事件保持 name 键兼容。 + const key = nameCounts.get(te.Name) > 1 && te.ToolCallId ? te.ToolCallId : te.Name; + tools[key] = entry; } return tools; } diff --git a/src/utils/session-message-history.ts b/src/utils/session-message-history.ts new file mode 100644 index 0000000..005f656 --- /dev/null +++ b/src/utils/session-message-history.ts @@ -0,0 +1,9 @@ +export function ownsOlderMessageScrollRequest(options: { + requestedSessionId: string; + activeSessionId: string | null; + requestToken: symbol; + activeRequestToken: symbol | null; +}): boolean { + return options.requestedSessionId === options.activeSessionId + && options.requestToken === options.activeRequestToken; +} From 73179669cc3a345846c420e87c49e15c5ec63f03 Mon Sep 17 00:00:00 2001 From: xiayu Date: Fri, 24 Jul 2026 16:30:23 +0800 Subject: [PATCH 02/61] feat(runtime): add AG-UI and A2UI hosted chat transport --- package-lock.json | 6437 ++++++++++++----- package.json | 11 +- postcss.config.js | 2 +- src/App.tsx | 11 +- src/__tests__/agui-run-client.test.ts | 196 + src/__tests__/agui-transport.test.ts | 60 + .../chat-message-list-contract.test.ts | 21 +- src/__tests__/messages-mapper.test.ts | 70 + src/__tests__/run-engine.test.ts | 185 + .../session-message-history-store.test.ts | 27 +- src/__tests__/streaming-store.test.ts | 19 + src/api/messages.ts | 10 + src/components/chat/A2UIActivityMessage.tsx | 49 + src/components/chat/ChatMessageList.tsx | 272 +- src/components/chat/ConnectedMessageList.tsx | 10 + src/components/chat/types.ts | 23 +- src/core/run/a2ui.ts | 56 + src/core/run/agui.ts | 257 + src/core/run/dispatcher.ts | 189 +- src/core/run/engine.ts | 143 +- src/core/run/types.ts | 39 +- src/core/stream/responses-protocol.ts | 1 + src/core/stream/types.ts | 18 + src/hooks/useRunAgent.ts | 65 +- src/hooks/useSessionLifecycle.ts | 5 + src/index.css | 31 +- src/stores/session.ts | 23 +- src/stores/streaming.ts | 59 +- src/types/api.ts | 16 +- src/types/capabilities.ts | 8 +- src/utils/capabilities.js | 55 + src/utils/messages.js | 30 +- src/utils/responses-stream.js | 101 +- tests/message-virtualization.test.mjs | 24 + tests/responses-stream.test.mjs | 30 + vite.config.ts | 2 +- 36 files changed, 6736 insertions(+), 1819 deletions(-) create mode 100644 src/__tests__/agui-run-client.test.ts create mode 100644 src/__tests__/agui-transport.test.ts create mode 100644 src/components/chat/A2UIActivityMessage.tsx create mode 100644 src/core/run/a2ui.ts create mode 100644 src/core/run/agui.ts diff --git a/package-lock.json b/package-lock.json index 8d8da26..0b892ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.2.19", "license": "Apache-2.0", "dependencies": { + "@ag-ui/client": "0.0.57", "@codemirror/autocomplete": "^6.20.2", "@codemirror/commands": "^6.10.3", "@codemirror/language": "^6.12.3", @@ -17,6 +18,8 @@ "@codemirror/state": "^6.6.0", "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.43.0", + "@copilotkit/a2ui-renderer": "^1.63.1", + "@copilotkit/react-core": "^1.63.1", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-dialog": "^1.1.15", @@ -25,7 +28,8 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", - "@tailwindcss/typography": "^0.5.19", + "@tailwindcss/postcss": "^4.3.3", + "@tailwindcss/typography": "^0.5.20", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", "class-variance-authority": "^0.7.1", @@ -44,10 +48,12 @@ "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", "uuid": "^13.0.0", + "zod": "^4.4.3", "zustand": "^5.0.13" }, "devDependencies": { "@eslint/js": "^9.39.4", + "@playwright/test": "^1.61.1", "@types/katex": "^0.16.8", "@types/node": "^24.12.0", "@types/react": "^19.2.14", @@ -64,7 +70,7 @@ "react": "^19.2.4", "react-dom": "^19.2.4", "rollup-plugin-visualizer": "^7.0.1", - "tailwindcss": "^3.4.3", + "tailwindcss": "^4.3.3", "typescript": "~5.9.3", "typescript-eslint": "^8.57.0", "vite": "^8.0.1", @@ -75,6 +81,116 @@ "react-dom": "^19.2.4" } }, + "node_modules/@0no-co/graphql.web": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.3.2.tgz", + "integrity": "sha512-Q1+pRlLhE31GOY/2c9BAEnFTNxO7Awtc6fhhEDlxyCBQ2N0IhD32cPVvPChrK9mwBNSgRdW/sF1kd2e0ojHj1Q==", + "license": "MIT", + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, + "node_modules/@a2ui/web_core": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@a2ui/web_core/-/web_core-0.9.0.tgz", + "integrity": "sha512-TsMWuEeuVDsScGIGPy/fWIZu+EOBRfhx6KwjKh3VwY1AwysRenQM8zDr8VrSk14Wck/aBgVxk2zWVrMCK2/s6A==", + "license": "Apache-2.0", + "dependencies": { + "@preact/signals-core": "^1.13.0", + "date-fns": "^4.1.0", + "zod": "^3.25.76", + "zod-to-json-schema": "^3.25.1" + } + }, + "node_modules/@a2ui/web_core/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@ag-ui/client": { + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/@ag-ui/client/-/client-0.0.57.tgz", + "integrity": "sha512-Xap2alG9Z0/j5kb3x4D7oTpe2sw1dfrC9rgJJr2NZu5vKcm8dzIPNd31mF2B4zS3BKqYIu245yxKPhEtT30MHw==", + "dependencies": { + "@ag-ui/core": "0.0.57", + "@ag-ui/encoder": "0.0.57", + "@ag-ui/proto": "0.0.57", + "@types/uuid": "^10.0.0", + "compare-versions": "^6.1.1", + "fast-json-patch": "^3.1.1", + "rxjs": "7.8.1", + "untruncate-json": "^0.0.1", + "uuid": "^11.1.0", + "zod": "^3.22.4" + } + }, + "node_modules/@ag-ui/client/node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/@ag-ui/client/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@ag-ui/core": { + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/@ag-ui/core/-/core-0.0.57.tgz", + "integrity": "sha512-gho1OWjNE6E3Rl7ZEZ1wr2CEpUHjLFU0FqzCZZk439TicLu+BfLCMkMokB07bMGlRmbJ60hM6LW60iOVauCx+Q==", + "dependencies": { + "zod": "^3.22.4" + } + }, + "node_modules/@ag-ui/core/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@ag-ui/encoder": { + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/@ag-ui/encoder/-/encoder-0.0.57.tgz", + "integrity": "sha512-ifD9NctR4xyPDR58xF9GK1bj/S8oECFkTeDfuYD8tXdbcOstIJ2TOqU2zhiCKnw7Vw+zR9Qv3TbsM9E7Gi9X3Q==", + "dependencies": { + "@ag-ui/core": "0.0.57", + "@ag-ui/proto": "0.0.57" + } + }, + "node_modules/@ag-ui/proto": { + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/@ag-ui/proto/-/proto-0.0.57.tgz", + "integrity": "sha512-pPENOZt0P6ibH8sCTgq05wLYXi5t3P9B5r/1bWYehXjUxtyOdnukSlWM++SsCIwUXsQdm/b3aBgGjEeTF7RenA==", + "dependencies": { + "@ag-ui/core": "0.0.57", + "@bufbuild/protobuf": "^2.2.5", + "@protobuf-ts/protoc": "^2.11.1" + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -355,6 +471,12 @@ "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", "license": "MIT" }, + "node_modules/@bufbuild/protobuf": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.13.0.tgz", + "integrity": "sha512-acq7c49vxfm1ggJ95P70TX7ABDM0vxr1SYD3BB0o0jnBLB4OAqeHyKuN+cD3w80gXEDQ2zxHpR6CUeA+O/aU9g==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, "node_modules/@chevrotain/types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", @@ -774,197 +896,1175 @@ "w3c-keyname": "^2.2.4" } }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, + "node_modules/@copilotkit/a2ui-renderer": { + "version": "1.63.1", + "resolved": "https://registry.npmjs.org/@copilotkit/a2ui-renderer/-/a2ui-renderer-1.63.1.tgz", + "integrity": "sha512-IsFT01Gyf2vwQZ0wvT5PGHS8P2UdIkXsZsedoBBju7HEoE2RJI0HPZB+zUxg41HuTI2NSgbACNsio4g2SxTj4A==", "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@a2ui/web_core": "0.9.0", + "clsx": "^2.1.1", + "lit": "^3.3.2", + "zod": "^3.25.75", + "zod-to-json-schema": "^3.24.1" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } } }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, + "node_modules/@copilotkit/a2ui-renderer/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", + "node_modules/@copilotkit/core": { + "version": "1.63.1", + "resolved": "https://registry.npmjs.org/@copilotkit/core/-/core-1.63.1.tgz", + "integrity": "sha512-Js7oHLtylw6sQQja/g7CunvF7l7dfhVq/n+NVNnuRbnvrq/xJxpEJfEsM+UomYxalB2pbtpqC+uxjnaoM5zk3A==", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@ag-ui/client": "0.0.57", + "@copilotkit/shared": "1.63.1", + "@tanstack/pacer": "^0.20.1", + "phoenix": "^1.8.4", + "rxjs": "7.8.1", + "zod-to-json-schema": "^3.24.6" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node_modules/@copilotkit/license-verifier": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@copilotkit/license-verifier/-/license-verifier-0.5.0.tgz", + "integrity": "sha512-vrwKtIpYwF0FT9ZoYASH8owa2cGV0dhDvJGaCRaRMStwDxpc6DRdydKkhx8cWZXyBRxEYcq/Vygv4JvevhQQdQ==", + "license": "MIT" + }, + "node_modules/@copilotkit/react-core": { + "version": "1.63.1", + "resolved": "https://registry.npmjs.org/@copilotkit/react-core/-/react-core-1.63.1.tgz", + "integrity": "sha512-Zv20Rebsh6VcvO00HDbh9B0Q6XnmEYygv8BKur0+OS4eRb1gR4QmWjff/+sjJgweFpgb645jY1i0FB4MU7j7pg==", + "license": "MIT", + "dependencies": { + "@ag-ui/client": "0.0.57", + "@ag-ui/core": "0.0.57", + "@copilotkit/a2ui-renderer": "1.63.1", + "@copilotkit/core": "1.63.1", + "@copilotkit/runtime-client-gql": "1.63.1", + "@copilotkit/shared": "1.63.1", + "@copilotkit/web-components": "1.63.1", + "@copilotkit/web-inspector": "1.63.1", + "@jetbrains/websandbox": "^1.1.3", + "@lit-labs/react": "^2.0.2", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tooltip": "^1.2.7", + "@scarf/scarf": "^1.3.0", + "@tanstack/react-virtual": "^3.13.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "katex": "^0.16.22", + "lit": "^3.3.2", + "lucide-react": "^0.525.0", + "react-markdown": "^8.0.7", + "rxjs": "7.8.1", + "streamdown": "^1.3.0", + "tailwind-merge": "^3.3.1", + "tw-animate-css": "^1.3.5", + "untruncate-json": "^0.0.1", + "use-stick-to-bottom": "^1.1.1", + "zod-to-json-schema": "^3.24.5" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc", + "zod": ">=3.0.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, + "node_modules/@copilotkit/react-core/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "dependencies": { + "@types/unist": "^2" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@copilotkit/react-core/node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "license": "MIT", "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "@types/unist": "^2" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node_modules/@copilotkit/react-core/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@copilotkit/react-core/node_modules/hast-util-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", + "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmmirror.com/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node_modules/@copilotkit/react-core/node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "license": "MIT" + }, + "node_modules/@copilotkit/react-core/node_modules/lucide-react": { + "version": "0.525.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz", + "integrity": "sha512-Tm1txJ2OkymCGkvwoHt33Y2JpN5xucVq1slHcgE6Lk0WjDfjgKWor5CdVER8U6DvcfMwh4M8XxmpTiyzfmfDYQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", - "dev": true, + "node_modules/@copilotkit/react-core/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", "license": "MIT", "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, + "node_modules/@copilotkit/react-core/node_modules/mdast-util-to-hast": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", + "integrity": "sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", - "dev": true, + "node_modules/@copilotkit/react-core/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "dependencies": { + "@types/mdast": "^3.0.0" }, "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@copilotkit/react-core/node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-decode-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/@copilotkit/react-core/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/@copilotkit/react-core/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@copilotkit/react-core/node_modules/react-markdown": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", + "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@copilotkit/react-core/node_modules/remark-parse": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", + "integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/remark-rehype": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/@copilotkit/react-core/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/unist-util-position": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", + "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/react-core/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@copilotkit/runtime-client-gql": { + "version": "1.63.1", + "resolved": "https://registry.npmjs.org/@copilotkit/runtime-client-gql/-/runtime-client-gql-1.63.1.tgz", + "integrity": "sha512-1nsCdQOmcoC9uyolyDPMduCYVNKusrorDvovb73PyedgQVRhRb4yK1QAhBDCJ8snvuMXkWT+hHBjkfvzExNKVA==", + "license": "MIT", + "dependencies": { + "@copilotkit/shared": "1.63.1", + "@urql/core": "^5.0.3", + "untruncate-json": "^0.0.1", + "urql": "^4.1.0" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/@copilotkit/shared": { + "version": "1.63.1", + "resolved": "https://registry.npmjs.org/@copilotkit/shared/-/shared-1.63.1.tgz", + "integrity": "sha512-jm7eNDS4AcA+s1lkOnd9U1BKelgGrFLXg64e5T4AVN5BUJyi2GRC67unBjT+9cvMgZGXI2Dj4jrsY5rQyiaXAw==", + "license": "MIT", + "dependencies": { + "@ag-ui/client": "0.0.57", + "@copilotkit/license-verifier": "~0.5.0", + "@segment/analytics-node": "^2.1.2", + "@standard-schema/spec": "^1.0.0", + "chalk": "4.1.2", + "graphql": "^16.8.1", + "partial-json": "^0.1.7", + "uuid": "^11.1.0", + "zod": "^3.23.3", + "zod-to-json-schema": "^3.23.5" + }, + "peerDependencies": { + "@ag-ui/core": ">=0.0.48" + } + }, + "node_modules/@copilotkit/shared/node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/@copilotkit/shared/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@copilotkit/web-components": { + "version": "1.63.1", + "resolved": "https://registry.npmjs.org/@copilotkit/web-components/-/web-components-1.63.1.tgz", + "integrity": "sha512-tH4ZS29nUAo2snVQ2tryDKbqBnZddUwodsLx2O847tFM6CdYenucr47IJp0Q3w5mDZznsb3fTdNGqg0o0w8Wiw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "lit": "^3.3.2" + } + }, + "node_modules/@copilotkit/web-inspector": { + "version": "1.63.1", + "resolved": "https://registry.npmjs.org/@copilotkit/web-inspector/-/web-inspector-1.63.1.tgz", + "integrity": "sha512-xgqYWNowTnNF3jnbk9ASACsOxYDNmv+JvDtwP6U2z413aMY0APWlYYQl616hJrXdQvBiJCgol+q8xFrjYB5xrg==", + "dependencies": { + "@ag-ui/client": "0.0.57", + "@copilotkit/core": "1.63.1", + "lit": "^3.2.0", + "lucide": "^0.525.0", + "marked": "^12.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@copilotkit/web-inspector/node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmmirror.com/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.1.tgz", @@ -972,396 +2072,1870 @@ "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=18.18.0" + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmmirror.com/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@iconify/utils/-/utils-3.1.0.tgz", + "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "mlly": "^1.8.0" + } + }, + "node_modules/@jetbrains/websandbox": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@jetbrains/websandbox/-/websandbox-1.3.1.tgz", + "integrity": "sha512-YTl3MJXbAkYDyuRhWqlQoo7eY2jaLGRqUkx4LVRvxr0VnK7s5bu0p2KAGOWZIBf6I3pmuuq+JzBDHw1b0fV0/Q==", + "license": "Apache-2.0" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lezer/common": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", + "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", + "license": "MIT" + }, + "node_modules/@lezer/cpp": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.5.tgz", + "integrity": "sha512-DIhSXmYtJKLehrjzDFN+2cPt547ySQ41nA8yqcDf/GxMc+YM736xqltFkvADL2M0VebU5I+3+4ks2Vv+Kyq3Aw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/css": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.3.tgz", + "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/go": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.1.tgz", + "integrity": "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz", + "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/java": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz", + "integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", + "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", + "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", + "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.6.3.tgz", + "integrity": "sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@lezer/php": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.5.tgz", + "integrity": "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.1.0" + } + }, + "node_modules/@lezer/python": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz", + "integrity": "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/rust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz", + "integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/sass": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/sass/-/sass-1.1.0.tgz", + "integrity": "sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/xml": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz", + "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/yaml": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.4.tgz", + "integrity": "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@lit-labs/react": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-2.1.3.tgz", + "integrity": "sha512-OD9h2JynerBQUMNzb563jiVpxfvPF0HjQkKY2mx0lpVYvD7F+rtJpOGz6ek+6ufMidV3i+MPT9SX62OKWHFrQg==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/react": "^1.0.3" + } + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.6.0.tgz", + "integrity": "sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/react": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@lit/react/-/react-1.0.8.tgz", + "integrity": "sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==", + "license": "BSD-3-Clause", + "peerDependencies": { + "@types/react": "17 || 18 || 19" + } + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", + "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0" + } + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@lukeed/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==", + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT" + }, + "node_modules/@mermaid-js/parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", + "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", + "license": "MIT", + "dependencies": { + "@chevrotain/types": "~11.1.1" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.132.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", + "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@playwright/test": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz", + "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.61.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@preact/signals-core": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.14.4.tgz", + "integrity": "sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@protobuf-ts/protoc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.11.1.tgz", + "integrity": "sha512-mUZJaV0daGO6HUX90o/atzQ6A7bbN2RSuHtdwo8SSF2Qoe3zHwa4IHyCN1evftTeHfLmdz+45qo47sL+5P8nyg==", + "license": "Apache-2.0", + "bin": { + "protoc": "protoc.js" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.13.tgz", + "integrity": "sha512-0Q310knIY0K+mkmncU9FxLggfW7V49Ok2oY+iu27KkERTsQXxYCIC8XW5QoK4w7Jp1z00vT5xj3oxTcn7QlcTg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.8" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/primitive": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", + "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.4.tgz", + "integrity": "sha512-pWJo6lQAfR6uy1n7ii7PaCc9dLPwTXDYbQpORZU5B548Aqvl2pP1SM1vJGKyxIFqZMHRopRO4CQYX2iXAIB5jA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.8.tgz", + "integrity": "sha512-DOlK1BdcIeYYUcFkSYFka4v1h95XTov93b0jCgW1EEiZuIhdwHY2NlE1teLIh+p0uBsuZI5A+voay+iVWpprfA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.3.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.1.tgz", + "integrity": "sha512-Bu/aAQHFFh6/QAvXAeUMurJ9fbW0JUIqlojU/yBXZ7cAVqy75Y7JYYyuCr9zLNF0p4WWoJYV54CTUIf4l7FzTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.22.tgz", + "integrity": "sha512-wZRLTjZaJf1HTxx0YepFKZUuo+SZMi+Cr4kJ2fuA5FxDSUE0vHDTscahUaU+jfz6LFk4OuguwqJs5K0JsIsIBA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-context": "1.2.1", + "@radix-ui/react-id": "1.1.3", + "@radix-ui/react-menu": "2.1.22", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-controllable-state": "1.2.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/primitive": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", + "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.4.tgz", + "integrity": "sha512-pWJo6lQAfR6uy1n7ii7PaCc9dLPwTXDYbQpORZU5B548Aqvl2pP1SM1vJGKyxIFqZMHRopRO4CQYX2iXAIB5jA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.1.tgz", + "integrity": "sha512-EraVbFjiIjibpLr6EjvEDmSCYJU2SlKDMiO+qEK/D9GOWnQoAQlpQo2occGYC1UM9MBeEx5Bek3UtW/Qi57vAg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-id": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.3.tgz", + "integrity": "sha512-f/Wxm0ctyMymUJK0fqTSQlm85rbzdAkoNbPXJQ5+6caowVO8Yx+NWGjGz/oGhs/D+WIbbQpOrU0hU2Li2/42xQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.8.tgz", + "integrity": "sha512-DOlK1BdcIeYYUcFkSYFka4v1h95XTov93b0jCgW1EEiZuIhdwHY2NlE1teLIh+p0uBsuZI5A+voay+iVWpprfA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.3.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.1.tgz", + "integrity": "sha512-Bu/aAQHFFh6/QAvXAeUMurJ9fbW0JUIqlojU/yBXZ7cAVqy75Y7JYYyuCr9zLNF0p4WWoJYV54CTUIf4l7FzTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.5.tgz", + "integrity": "sha512-UB1dXpxvHjR48poyKdKdTm7jT0kp3elkUKdKQiOkirlbYumqXinSJtrjDsr9maXNPvL12bKI4CDSmydms/9Aeg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-use-effect-event": "0.0.4", + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.4.tgz", + "integrity": "sha512-XYcfa6wlXDCwQtePuEiPmXLSAhGL4DWtedSyRgGbG3y10mw+OnrLp6SyeY1gJFMiYF0Dx0nMAX9InylKbLEFQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.3.tgz", + "integrity": "sha512-rDiah9wvtqihWtWz02XreeRKIxt2EJF8y5D9rtY9l5A2zxePAtcPiOMpDugNRw5bFHz+1/8viVoc7ZVKiJknCw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmmirror.com/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@radix-ui/react-menu": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.22.tgz", + "integrity": "sha512-xCFrVLttGDPwMjIPI6GS+tm3IGUNKsPXffrJQIPpQJuE9Qy1bU9GNUCkwranU/pEqyBlwMxcBIK/FUJFAZ9SqQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.13", + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-context": "1.2.1", + "@radix-ui/react-direction": "1.1.3", + "@radix-ui/react-dismissable-layer": "1.1.17", + "@radix-ui/react-focus-guards": "1.1.5", + "@radix-ui/react-focus-scope": "1.1.14", + "@radix-ui/react-id": "1.1.3", + "@radix-ui/react-popper": "1.3.5", + "@radix-ui/react-portal": "1.1.15", + "@radix-ui/react-presence": "1.1.9", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-roving-focus": "1.1.17", + "@radix-ui/react-slot": "1.3.1", + "@radix-ui/react-use-callback-ref": "1.1.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/primitive": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", + "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-collection": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.13.tgz", + "integrity": "sha512-Q8xYqNRFObXPmi45bFSkGdM2JA5hjBeYGFqzg6lZR3wp6b+cciraVq8DdneTabtws+uOYqjmsvmKOufk/M9Cyg==", + "license": "MIT", "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-context": "1.2.1", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-slot": "1.3.1" }, - "engines": { - "node": ">=18.18.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.4.tgz", + "integrity": "sha512-pWJo6lQAfR6uy1n7ii7PaCc9dLPwTXDYbQpORZU5B548Aqvl2pP1SM1vJGKyxIFqZMHRopRO4CQYX2iXAIB5jA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.1.tgz", + "integrity": "sha512-EraVbFjiIjibpLr6EjvEDmSCYJU2SlKDMiO+qEK/D9GOWnQoAQlpQo2occGYC1UM9MBeEx5Bek3UtW/Qi57vAg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "license": "MIT" + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-direction": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.3.tgz", + "integrity": "sha512-OdgAA/xb6WOQMKNn0mtbYoruMG6YMaBOnq+evWxSpMmiEMBdeFZawnIWRfPPeVXCRm+0lnN8jpJLjhD7/UIxWw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@iconify/utils": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/@iconify/utils/-/utils-3.1.0.tgz", - "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.17.tgz", + "integrity": "sha512-QAXwa38pG0xNAYh1pjdSaf86NrkqsMoDNmget/Y7X8O8E/C3Iqlj9GAPE4DfX9BPLXc7WH2TWSzMRnIoCdcjzQ==", "license": "MIT", "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/types": "^2.0.0", - "mlly": "^1.8.0" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-callback-ref": "1.1.3", + "@radix-ui/react-use-effect-event": "0.0.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.5.tgz", + "integrity": "sha512-UQvlB7L/BYh3P8MLvwZnQkH521EDos40Rwnbt5+Qpg4Vbk0z3xJjRUmR6+aka4aT1IQQXFdO5bNPoE7cvFl5xQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.14.tgz", + "integrity": "sha512-/x4htnJfmW53MplkrePaDpf1o/rN1C++g88WpVobULXbSyC19NtLkXmewuJ/HCaceSmfKDNL5gOXcBGnuAvnvQ==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-callback-ref": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-id": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.3.tgz", + "integrity": "sha512-f/Wxm0ctyMymUJK0fqTSQlm85rbzdAkoNbPXJQ5+6caowVO8Yx+NWGjGz/oGhs/D+WIbbQpOrU0hU2Li2/42xQ==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.15.tgz", + "integrity": "sha512-kAfBVJUKNNKZuyGQXXG6rKolAV2KAmxxVkPXJgoq9dEFTl39286RufHQFNTL8rzha4vP8159BJ6hMGpB+bqv7A==", "license": "MIT", - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.9.tgz", + "integrity": "sha512-LTi1v05bprIb8/GSY/GWusI0jfsYjQ3CD3Nin8o7jVxnpHzVQfzjOQJoJTQkE9bdmOnsS7SFdhkXiBv8PrYnxw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.8.tgz", + "integrity": "sha512-DOlK1BdcIeYYUcFkSYFka4v1h95XTov93b0jCgW1EEiZuIhdwHY2NlE1teLIh+p0uBsuZI5A+voay+iVWpprfA==", "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@radix-ui/react-slot": "1.3.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.17.tgz", + "integrity": "sha512-YdJmjETw7Py+4Nziv71jgZ6fH7xQgB5p+pQ5rV8Iufyrm0RHSijec/UV1zPfQoK/YcfzB9nOl/2bi1zf1SjRMQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.13", + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-context": "1.2.1", + "@radix-ui/react-direction": "1.1.3", + "@radix-ui/react-id": "1.1.3", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-callback-ref": "1.1.3", + "@radix-ui/react-use-controllable-state": "1.2.5", + "@radix-ui/react-use-is-hydrated": "0.1.2", + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@lezer/common": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", - "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", - "license": "MIT" - }, - "node_modules/@lezer/cpp": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.5.tgz", - "integrity": "sha512-DIhSXmYtJKLehrjzDFN+2cPt547ySQ41nA8yqcDf/GxMc+YM736xqltFkvADL2M0VebU5I+3+4ks2Vv+Kyq3Aw==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.1.tgz", + "integrity": "sha512-Bu/aAQHFFh6/QAvXAeUMurJ9fbW0JUIqlojU/yBXZ7cAVqy75Y7JYYyuCr9zLNF0p4WWoJYV54CTUIf4l7FzTw==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/css": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.3.tgz", - "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.3.tgz", + "integrity": "sha512-AUS7HoBBAncIsGMLNG+CcpLuJ+JIBbZzmyM8Qdb1eIThX0AlhSSC6wn40xfBlPE+ypx/vSSiRWnklUAjy3U3UA==", "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.3.0" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/go": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.1.tgz", - "integrity": "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.5.tgz", + "integrity": "sha512-UB1dXpxvHjR48poyKdKdTm7jT0kp3elkUKdKQiOkirlbYumqXinSJtrjDsr9maXNPvL12bKI4CDSmydms/9Aeg==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.3.0" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-use-effect-event": "0.0.4", + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/highlight": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", - "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.4.tgz", + "integrity": "sha512-XYcfa6wlXDCwQtePuEiPmXLSAhGL4DWtedSyRgGbG3y10mw+OnrLp6SyeY1gJFMiYF0Dx0nMAX9InylKbLEFQQ==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.3.0" + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/html": { - "version": "1.3.13", - "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz", - "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.2.tgz", + "integrity": "sha512-2+gAVu9uaSLbopCTvvuWX9MIgEOlyqXC1Ok+KLCO7cZPSHLENs7dL0KbFQUGFIcFKmDW/bmaQRJtd8E3cnMRUw==", "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/java": { + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-layout-effect": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz", - "integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.3.tgz", + "integrity": "sha512-rDiah9wvtqihWtWz02XreeRKIxt2EJF8y5D9rtY9l5A2zxePAtcPiOMpDugNRw5bFHz+1/8viVoc7ZVKiJknCw==", "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/javascript": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", - "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.1.3", - "@lezer/lr": "^1.3.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@lezer/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", - "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "node_modules/@radix-ui/react-popper": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.5.tgz", + "integrity": "sha512-6hLng2Rs45IZcvZ31BNvMeaFEMMEbtsog4xPcb8LZrGfyoV9fdAXqB9UKhLpTHtL0+E2DhSr6VW54Tehd6ksAQ==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.13", + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-context": "1.2.1", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-callback-ref": "1.1.3", + "@radix-ui/react-use-layout-effect": "1.1.3", + "@radix-ui/react-use-rect": "1.1.3", + "@radix-ui/react-use-size": "1.1.3", + "@radix-ui/rect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@lezer/lr": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", - "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/primitive": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", + "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.4.tgz", + "integrity": "sha512-pWJo6lQAfR6uy1n7ii7PaCc9dLPwTXDYbQpORZU5B548Aqvl2pP1SM1vJGKyxIFqZMHRopRO4CQYX2iXAIB5jA==", "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/markdown": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.6.3.tgz", - "integrity": "sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw==", + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.1.tgz", + "integrity": "sha512-EraVbFjiIjibpLr6EjvEDmSCYJU2SlKDMiO+qEK/D9GOWnQoAQlpQo2occGYC1UM9MBeEx5Bek3UtW/Qi57vAg==", "license": "MIT", - "dependencies": { - "@lezer/common": "^1.5.0", - "@lezer/highlight": "^1.0.0" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/php": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.5.tgz", - "integrity": "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==", + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.8.tgz", + "integrity": "sha512-DOlK1BdcIeYYUcFkSYFka4v1h95XTov93b0jCgW1EEiZuIhdwHY2NlE1teLIh+p0uBsuZI5A+voay+iVWpprfA==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.1.0" + "@radix-ui/react-slot": "1.3.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@lezer/python": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz", - "integrity": "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==", + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.1.tgz", + "integrity": "sha512-Bu/aAQHFFh6/QAvXAeUMurJ9fbW0JUIqlojU/yBXZ7cAVqy75Y7JYYyuCr9zLNF0p4WWoJYV54CTUIf4l7FzTw==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/rust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz", - "integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==", + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.3.tgz", + "integrity": "sha512-AUS7HoBBAncIsGMLNG+CcpLuJ+JIBbZzmyM8Qdb1eIThX0AlhSSC6wn40xfBlPE+ypx/vSSiRWnklUAjy3U3UA==", "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.3.tgz", + "integrity": "sha512-rDiah9wvtqihWtWz02XreeRKIxt2EJF8y5D9rtY9l5A2zxePAtcPiOMpDugNRw5bFHz+1/8viVoc7ZVKiJknCw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@lezer/sass": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lezer/sass/-/sass-1.1.0.tgz", - "integrity": "sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ==", + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@lezer/xml": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz", - "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==", + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@lezer/yaml": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.4.tgz", - "integrity": "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==", + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.4.0" + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@marijn/find-cluster-break": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", - "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", - "license": "MIT" - }, - "node_modules/@mermaid-js/parser": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", - "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { - "@chevrotain/types": "~11.1.1" + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", "license": "MIT", - "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@radix-ui/react-slot": "1.2.4" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@oxc-project/types": { - "version": "0.132.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", - "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", - "dev": true, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", - "license": "MIT" - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", - "license": "MIT" + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@radix-ui/react-accordion": { - "version": "1.2.12", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", - "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collapsible": "1.1.12", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { @@ -1379,17 +3953,25 @@ } } }, - "node_modules/@radix-ui/react-avatar": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", - "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-context": "1.1.3", - "@radix-ui/react-primitive": "2.1.4", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.14.tgz", + "integrity": "sha512-C/JxCKJJac+wtHPW1yFBSN8Ssuaufy2jYQMgyiJYyW4Fw0WJfDWXQDAly1qsbd1YDznH+sYitaljhf8igPCvmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-context": "1.2.1", + "@radix-ui/react-dismissable-layer": "1.1.17", + "@radix-ui/react-id": "1.1.3", + "@radix-ui/react-popper": "1.3.5", + "@radix-ui/react-portal": "1.1.15", + "@radix-ui/react-presence": "1.1.9", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-slot": "1.3.1", + "@radix-ui/react-use-controllable-state": "1.2.5", + "@radix-ui/react-use-layout-effect": "1.1.3", + "@radix-ui/react-visually-hidden": "1.2.9" }, "peerDependencies": { "@types/react": "*", @@ -1406,10 +3988,16 @@ } } }, - "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.1.3.tgz", - "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", + "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.4.tgz", + "integrity": "sha512-pWJo6lQAfR6uy1n7ii7PaCc9dLPwTXDYbQpORZU5B548Aqvl2pP1SM1vJGKyxIFqZMHRopRO4CQYX2iXAIB5jA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1421,13 +4009,32 @@ } } }, - "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.1.tgz", + "integrity": "sha512-EraVbFjiIjibpLr6EjvEDmSCYJU2SlKDMiO+qEK/D9GOWnQoAQlpQo2occGYC1UM9MBeEx5Bek3UtW/Qi57vAg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.17.tgz", + "integrity": "sha512-QAXwa38pG0xNAYh1pjdSaf86NrkqsMoDNmget/Y7X8O8E/C3Iqlj9GAPE4DfX9BPLXc7WH2TWSzMRnIoCdcjzQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4", + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-callback-ref": "1.1.3", + "@radix-ui/react-use-effect-event": "0.0.4" }, "peerDependencies": { "@types/react": "*", @@ -1444,20 +4051,32 @@ } } }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.12", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", - "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-id": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.3.tgz", + "integrity": "sha512-f/Wxm0ctyMymUJK0fqTSQlm85rbzdAkoNbPXJQ5+6caowVO8Yx+NWGjGz/oGhs/D+WIbbQpOrU0hU2Li2/42xQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.15.tgz", + "integrity": "sha512-kAfBVJUKNNKZuyGQXXG6rKolAV2KAmxxVkPXJgoq9dEFTl39286RufHQFNTL8rzha4vP8159BJ6hMGpB+bqv7A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.8", + "@radix-ui/react-use-layout-effect": "1.1.3" }, "peerDependencies": { "@types/react": "*", @@ -1474,16 +4093,13 @@ } } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.9.tgz", + "integrity": "sha512-LTi1v05bprIb8/GSY/GWusI0jfsYjQ3CD3Nin8o7jVxnpHzVQfzjOQJoJTQkE9bdmOnsS7SFdhkXiBv8PrYnxw==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-use-layout-effect": "1.1.3" }, "peerDependencies": { "@types/react": "*", @@ -1500,29 +4116,38 @@ } } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.8.tgz", + "integrity": "sha512-DOlK1BdcIeYYUcFkSYFka4v1h95XTov93b0jCgW1EEiZuIhdwHY2NlE1teLIh+p0uBsuZI5A+voay+iVWpprfA==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/react-slot": "1.3.1" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.1.tgz", + "integrity": "sha512-Bu/aAQHFFh6/QAvXAeUMurJ9fbW0JUIqlojU/yBXZ7cAVqy75Y7JYYyuCr9zLNF0p4WWoJYV54CTUIf4l7FzTw==", "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.4" + }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1533,10 +4158,10 @@ } } }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.3.tgz", + "integrity": "sha512-AUS7HoBBAncIsGMLNG+CcpLuJ+JIBbZzmyM8Qdb1eIThX0AlhSSC6wn40xfBlPE+ypx/vSSiRWnklUAjy3U3UA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1548,49 +4173,33 @@ } } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", - "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.5.tgz", + "integrity": "sha512-UB1dXpxvHjR48poyKdKdTm7jT0kp3elkUKdKQiOkirlbYumqXinSJtrjDsr9maXNPvL12bKI4CDSmydms/9Aeg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-use-effect-event": "0.0.4", + "@radix-ui/react-use-layout-effect": "1.1.3" }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.4.tgz", + "integrity": "sha512-XYcfa6wlXDCwQtePuEiPmXLSAhGL4DWtedSyRgGbG3y10mw+OnrLp6SyeY1gJFMiYF0Dx0nMAX9InylKbLEFQQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/react-use-layout-effect": "1.1.3" }, "peerDependencies": { "@types/react": "*", @@ -1602,10 +4211,10 @@ } } }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.3.tgz", + "integrity": "sha512-rDiah9wvtqihWtWz02XreeRKIxt2EJF8y5D9rtY9l5A2zxePAtcPiOMpDugNRw5bFHz+1/8viVoc7ZVKiJknCw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1617,17 +4226,13 @@ } } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.9.tgz", + "integrity": "sha512-seuZXNZVCz1kLSQMRO/TdNOSahBI3S5nXE4jzO7u7aFRWQlMAnwyrr8vKMkEU115fCLEyzR2YyjnP+aRMxK34w==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" + "@radix-ui/react-primitive": "2.1.8" }, "peerDependencies": { "@types/react": "*", @@ -1644,10 +4249,10 @@ } } }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", - "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1659,35 +4264,29 @@ } } }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1702,121 +4301,113 @@ } } }, - "node_modules/@radix-ui/react-navigation-menu": { - "version": "1.2.14", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", - "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" + "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { "optional": true } } }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.3.tgz", + "integrity": "sha512-W0GSYZFKEfi6raMiMEfJSngvVbFDIyxtW5JuVg5NoQBY59l0dVQVGLbhog/tOdwq0qtZ+TXuX1ikSNan4/IZXA==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.3.tgz", + "integrity": "sha512-jJq6tQQLvO/z4uWbztjwPV+1a/+H4rCaWypasLB/ac8DEdd6+p7dIm7o3F6P2KZPGkPMqD4s5424EdAdoU+GLA==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-use-layout-effect": "1.1.3" }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@radix-ui/react-use-size/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.3.tgz", + "integrity": "sha512-rDiah9wvtqihWtWz02XreeRKIxt2EJF8y5D9rtY9l5A2zxePAtcPiOMpDugNRw5bFHz+1/8viVoc7ZVKiJknCw==", "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1827,21 +4418,13 @@ } } }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", - "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -1858,553 +4441,803 @@ } } }, - "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.10", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", - "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "node_modules/@radix-ui/rect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.3.tgz", + "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", + "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", + "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", + "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", + "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", + "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", + "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", + "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", + "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", + "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", + "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", + "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.8", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", - "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", + "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", + "cpu": [ + "wasm32" + ], + "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", + "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", - "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", + "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", - "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, + "node_modules/@segment/analytics-core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@segment/analytics-core/-/analytics-core-1.8.2.tgz", + "integrity": "sha512-5FDy6l8chpzUfJcNlIcyqYQq4+JTUynlVoCeCUuVz+l+6W0PXg+ljKp34R4yLVCcY5VVZohuW+HH0VLWdwYVAg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@lukeed/uuid": "^2.0.0", + "@segment/analytics-generic-utils": "1.2.0", + "dset": "^3.1.4", + "tslib": "^2.4.1" } }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "node_modules/@segment/analytics-generic-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@segment/analytics-generic-utils/-/analytics-generic-utils-1.2.0.tgz", + "integrity": "sha512-DfnW6mW3YQOLlDQQdR89k4EqfHb0g/3XvBXkovH1FstUN93eL1kfW9CsDcVQyH3bAC5ZsFyjA/o/1Q2j0QeoWw==", "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "dependencies": { + "tslib": "^2.4.1" } }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "node_modules/@segment/analytics-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@segment/analytics-node/-/analytics-node-2.3.0.tgz", + "integrity": "sha512-fOXLL8uY0uAWw/sTLmezze80hj8YGgXXlAfvSS6TUmivk4D/SP0C0sxnbpFdkUzWg2zT64qWIZj26afEtSnxUA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@lukeed/uuid": "^2.0.0", + "@segment/analytics-core": "1.8.2", + "@segment/analytics-generic-utils": "1.2.0", + "buffer": "^6.0.3", + "jose": "^5.1.0", + "node-fetch": "^2.6.7", + "tslib": "^2.4.1" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": ">=20" } }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "node_modules/@shikijs/core": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" } }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "node_modules/@shikijs/engine-javascript": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" } }, - "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", - "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", "license": "MIT", "dependencies": { - "use-sync-external-store": "^1.5.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "node_modules/@shikijs/langs": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "dependencies": { + "@shikijs/types": "3.23.0" } }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", - "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" } }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", - "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", - "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", - "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", - "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", - "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", - "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", - "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", - "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", "cpu": [ - "ppc64" + "x64" + ], + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", - "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", "cpu": [ - "s390x" + "x64" + ], + "libc": [ + "musl" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", - "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], "cpu": [ - "x64" + "wasm32" ], - "dev": true, "license": "MIT", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=14.0.0" } }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", - "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "inBundle": true, "license": "MIT", "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" } }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", - "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "inBundle": true, "license": "MIT", "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", - "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", - "cpu": [ - "wasm32" - ], - "dev": true, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "inBundle": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" }, - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", - "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "inBundle": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", - "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 20" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.7", - "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", - "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", - "dev": true, - "license": "MIT" + "node_modules/@tailwindcss/postcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz", + "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "postcss": "^8.5.16", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.20.tgz", + "integrity": "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >=4.0.0 || insiders" + } + }, + "node_modules/@tanstack/devtools-event-client": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@tanstack/devtools-event-client/-/devtools-event-client-0.4.4.tgz", + "integrity": "sha512-6T5Yop/793YI+H+5J8Hsyj4kCih9sl4t3ElLgKioW5hk3ocn+ZdSJ94tT7vL7uabxSugWYBZlOTMPzEw2puvQw==", + "license": "MIT", + "bin": { + "intent": "bin/intent.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" + "node_modules/@tanstack/pacer": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@tanstack/pacer/-/pacer-0.20.1.tgz", + "integrity": "sha512-ZNQ1bIL6eUXVKdic0tiImvBVkWrg/IoSK6VIacTrO3d3HAGnd70qFJNJagR/YOJIOw4EKGWnodwpYZkN1pWuVQ==", + "license": "MIT", + "dependencies": { + "@tanstack/devtools-event-client": "^0.4.3", + "@tanstack/store": "^0.9.3" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } }, - "node_modules/@tailwindcss/typography": { - "version": "0.5.19", - "resolved": "https://registry.npmmirror.com/@tailwindcss/typography/-/typography-0.5.19.tgz", - "integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==", + "node_modules/@tanstack/react-virtual": { + "version": "3.14.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.8.tgz", + "integrity": "sha512-O39GJQpAYEJcIu3uN1//YtmhjSEOyw75vg9CKCatBDPiD5hKtZQoJHfferyrB/LdOD3UWaoMLWtdEjarwIwdDw==", "license": "MIT", "dependencies": { - "postcss-selector-parser": "6.0.10" + "@tanstack/virtual-core": "3.17.6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/store": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", + "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.6", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.6.tgz", + "integrity": "sha512-h0/Ebo18CkOrChlQIhNtQkM5ySUnh/GumQ/D1st3hG2HWUPEF+ILUc2k29UtivCi/9G7w7G3/f7Xyd5cCFbKBw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tybys/wasm-util": { @@ -2772,6 +5605,12 @@ "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", "license": "MIT" }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.2.14", "resolved": "https://registry.npmmirror.com/@types/react/-/react-19.2.14.tgz", @@ -2805,8 +5644,7 @@ "version": "2.0.7", "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/@types/unist": { "version": "3.0.3", @@ -2818,7 +5656,6 @@ "version": "10.0.0", "resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-10.0.0.tgz", "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -3132,6 +5969,16 @@ "d3-transition": "^3.0.1" } }, + "node_modules/@urql/core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz", + "integrity": "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.13", + "wonka": "^6.3.2" + } + }, "node_modules/@vitejs/plugin-react": { "version": "6.0.1", "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", @@ -3342,7 +6189,6 @@ "version": "4.3.0", "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -3354,31 +6200,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "license": "MIT" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", @@ -3462,6 +6283,26 @@ "dev": true, "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/baseline-browser-mapping": { "version": "2.10.12", "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz", @@ -3475,18 +6316,6 @@ "node": ">=6.0.0" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/brace-expansion": { "version": "1.1.13", "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.13.tgz", @@ -3498,18 +6327,6 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.1.tgz", @@ -3544,6 +6361,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -3570,15 +6411,6 @@ "node": ">=6" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001782", "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz", @@ -3624,7 +6456,6 @@ "version": "4.1.2", "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -3677,42 +6508,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -3768,7 +6563,6 @@ "version": "2.0.1", "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -3781,7 +6575,6 @@ "version": "1.1.4", "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/comma-separated-tokens": { @@ -3794,14 +6587,11 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", @@ -4379,6 +7169,16 @@ "lodash-es": "^4.17.21" } }, + "node_modules/date-fns": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/dayjs": { "version": "1.11.20", "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.20.tgz", @@ -4487,7 +7287,6 @@ "version": "2.1.2", "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -4512,17 +7311,14 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "license": "Apache-2.0" - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "license": "MIT" + "node_modules/diff": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } }, "node_modules/dompurify": { "version": "3.4.7", @@ -4533,6 +7329,15 @@ "@types/trusted-types": "^2.0.7" } }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.329", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.329.tgz", @@ -4547,6 +7352,19 @@ "dev": true, "license": "MIT" }, + "node_modules/enhanced-resolve": { + "version": "5.24.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", + "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz", @@ -4835,33 +7653,11 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", @@ -4877,15 +7673,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/fault": { "version": "1.0.4", "resolved": "https://registry.npmmirror.com/fault/-/fault-1.0.4.tgz", @@ -4912,18 +7699,6 @@ "node": ">=16.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", @@ -5015,6 +7790,7 @@ "version": "2.3.3", "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -5025,15 +7801,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5058,7 +7825,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5080,6 +7846,7 @@ "version": "6.0.2", "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -5101,6 +7868,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphql": { + "version": "16.14.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.2.tgz", + "integrity": "sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, "node_modules/hachure-fill": { "version": "0.5.2", "resolved": "https://registry.npmmirror.com/hachure-fill/-/hachure-fill-0.5.2.tgz", @@ -5111,23 +7893,17 @@ "version": "4.0.0", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } + "node_modules/hast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hast/-/hast-1.0.0.tgz", + "integrity": "sha512-vFUqlRV5C+xqP76Wwq2SrM0kipnmpxJm7OfvVXpB35Fp+Fn4MV+ozr+JZr5qFvyR1q/U+Foim2x+3P+x9S1PLA==", + "deprecated": "Renamed to rehype", + "license": "MIT" }, "node_modules/hast-util-from-dom": { "version": "5.0.1", @@ -5190,34 +7966,97 @@ "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", - "vfile-location": "^5.0.0", - "web-namespaces": "^2.0.0" + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-is-element": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "node_modules/hast-util-sanitize": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-5.0.2.tgz", + "integrity": "sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==", "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0" + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "unist-util-position": "^5.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-parse-selector": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" }, "funding": { "type": "opencollective", @@ -5251,6 +8090,25 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-text": { "version": "4.0.2", "resolved": "https://registry.npmmirror.com/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", @@ -5339,6 +8197,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -5351,6 +8219,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", @@ -5427,31 +8315,27 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, "node_modules/is-decimal": { @@ -5484,6 +8368,7 @@ "version": "2.1.1", "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5493,6 +8378,7 @@ "version": "4.0.3", "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -5543,15 +8429,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -5588,19 +8465,27 @@ "license": "ISC" }, "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmmirror.com/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "license": "MIT", "bin": { - "jiti": "bin/jiti.js" + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" } }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -5703,6 +8588,15 @@ "resolved": "https://registry.npmmirror.com/khroma/-/khroma-2.1.0.tgz", "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/layout-base": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/layout-base/-/layout-base-1.0.2.tgz", @@ -5727,7 +8621,6 @@ "version": "1.32.0", "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz", "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -5760,7 +8653,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5781,7 +8673,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5802,7 +8693,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5823,7 +8713,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5844,7 +8733,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5865,7 +8753,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5886,7 +8773,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5907,7 +8793,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5928,7 +8813,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5949,7 +8833,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5970,7 +8853,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -5984,23 +8866,36 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" + "node_modules/lit": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.3.tgz", + "integrity": "sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" + "node_modules/lit-element": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", + "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.3.tgz", + "integrity": "sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } }, "node_modules/locate-path": { "version": "6.0.0", @@ -6041,6 +8936,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lowlight": { "version": "1.20.0", "resolved": "https://registry.npmmirror.com/lowlight/-/lowlight-1.20.0.tgz", @@ -6065,6 +8972,12 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide": { + "version": "0.525.0", + "resolved": "https://registry.npmjs.org/lucide/-/lucide-0.525.0.tgz", + "integrity": "sha512-sfehWlaE/7NVkcEQ4T9JD3eID8RNMIGJBBUq9wF3UFiJIrcMKRbU3g1KGfDk4svcW7yw8BtDLXaXo02scDtUYQ==", + "license": "ISC" + }, "node_modules/lucide-react": { "version": "1.7.0", "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-1.7.0.tgz", @@ -6078,7 +8991,6 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -6106,6 +9018,78 @@ "node": ">= 20" } }, + "node_modules/mdast-util-definitions": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", + "integrity": "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/mdast-util-definitions/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmmirror.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -6407,15 +9391,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/mermaid": { "version": "11.15.0", "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", @@ -6496,22 +9471,93 @@ ], "license": "MIT", "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-cjk-friendly": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/micromark-extension-cjk-friendly/-/micromark-extension-cjk-friendly-1.2.3.tgz", + "integrity": "sha512-gRzVLUdjXBLX6zNPSnHGDoo+ZTp5zy+MZm0g3sv+3chPXY7l9gW+DnrcHcZh/jiPR6MjPKO4AEJNp4Aw6V9z5Q==", + "license": "MIT", + "dependencies": { + "devlop": "^1.1.0", + "micromark-extension-cjk-friendly-util": "2.1.1", + "micromark-util-chunked": "^2.0.1", + "micromark-util-resolve-all": "^2.0.1", + "micromark-util-symbol": "^2.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "micromark": "^4.0.0", + "micromark-util-types": "^2.0.0" + }, + "peerDependenciesMeta": { + "micromark-util-types": { + "optional": true + } + } + }, + "node_modules/micromark-extension-cjk-friendly-gfm-strikethrough": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/micromark-extension-cjk-friendly-gfm-strikethrough/-/micromark-extension-cjk-friendly-gfm-strikethrough-1.2.3.tgz", + "integrity": "sha512-gSPnxgHDDqXYOBvQRq6lerrq9mjDhdtKn+7XETuXjxWcL62yZEfUdA28Ml1I2vDIPfAOIKLa0h2XDSGkInGHFQ==", + "license": "MIT", + "dependencies": { + "devlop": "^1.1.0", + "get-east-asian-width": "^1.3.0", + "micromark-extension-cjk-friendly-util": "2.1.1", + "micromark-util-character": "^2.1.1", + "micromark-util-chunked": "^2.0.1", + "micromark-util-resolve-all": "^2.0.1", + "micromark-util-symbol": "^2.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "micromark": "^4.0.0", + "micromark-util-types": "^2.0.0" + }, + "peerDependenciesMeta": { + "micromark-util-types": { + "optional": true + } + } + }, + "node_modules/micromark-extension-cjk-friendly-util": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-cjk-friendly-util/-/micromark-extension-cjk-friendly-util-2.1.1.tgz", + "integrity": "sha512-egs6+12JU2yutskHY55FyR48ZiEcFOJFyk9rsiyIhcJ6IvWB6ABBqVrBw8IobqJTDZ/wdSr9eoXDPb5S2nW1bg==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "micromark-util-character": "^2.1.1", + "micromark-util-symbol": "^2.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependenciesMeta": { + "micromark-util-types": { + "optional": true + } } }, "node_modules/micromark-extension-gfm": { @@ -7027,19 +10073,6 @@ ], "license": "MIT" }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", @@ -7080,27 +10113,25 @@ "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", "license": "MIT" }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -7122,6 +10153,26 @@ "dev": true, "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.36", "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.36.tgz", @@ -7129,15 +10180,6 @@ "dev": true, "license": "MIT" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", @@ -7147,15 +10189,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -7167,6 +10200,23 @@ ], "license": "MIT" }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, "node_modules/open": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", @@ -7294,6 +10344,12 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, "node_modules/path-data-parser": { "version": "0.1.0", "resolved": "https://registry.npmmirror.com/path-data-parser/-/path-data-parser-0.1.0.tgz", @@ -7320,45 +10376,24 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "license": "MIT" }, + "node_modules/phoenix": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/phoenix/-/phoenix-1.8.9.tgz", + "integrity": "sha512-/2qzAZB3P2s08fFAYaG65lqaNFmVXUSlXdY4/JDdDKIC81y2cFWkPwI8gycy4VLpv197JwZ5PpBf3VhoG32yGA==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmmirror.com/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/pkg-types": { "version": "1.3.1", "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.1.tgz", @@ -7370,6 +10405,53 @@ "pathe": "^2.0.1" } }, + "node_modules/playwright": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", + "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.61.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz", + "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/points-on-curve": { "version": "0.2.0", "resolved": "https://registry.npmmirror.com/points-on-curve/-/points-on-curve-0.2.0.tgz", @@ -7387,9 +10469,9 @@ } }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", + "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", "funding": [ { "type": "opencollective", @@ -7406,7 +10488,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7414,128 +10496,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-nested/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss-selector-parser": { "version": "6.0.10", "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", @@ -7553,6 +10513,7 @@ "version": "4.2.0", "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, "license": "MIT" }, "node_modules/powershell-utils": { @@ -7587,6 +10548,23 @@ "node": ">=6" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmmirror.com/property-information/-/property-information-7.1.0.tgz", @@ -7607,26 +10585,6 @@ "node": ">=6" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/react": { "version": "19.2.4", "resolved": "https://registry.npmmirror.com/react/-/react-19.2.4.tgz", @@ -7648,6 +10606,12 @@ "react": "^19.2.4" } }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, "node_modules/react-markdown": { "version": "10.1.0", "resolved": "https://registry.npmmirror.com/react-markdown/-/react-markdown-10.1.0.tgz", @@ -7764,36 +10728,6 @@ "react": ">= 0.14.0" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/read-cache/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/refractor": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/refractor/-/refractor-5.0.0.tgz", @@ -7810,6 +10744,39 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/rehype-harden": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/rehype-harden/-/rehype-harden-1.1.8.tgz", + "integrity": "sha512-Qn7vR1xrf6fZCrkm9TDWi/AB4ylrHy+jqsNm1EHOAmbARYA6gsnVJBq/sdBh6kmT4NEZxH5vgIjrscefJAOXcw==", + "license": "MIT", + "dependencies": { + "unist-util-visit": "^5.0.0" + } + }, "node_modules/rehype-katex": { "version": "7.0.1", "resolved": "https://registry.npmmirror.com/rehype-katex/-/rehype-katex-7.0.1.tgz", @@ -7829,6 +10796,77 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-sanitize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-sanitize/-/rehype-sanitize-6.0.0.tgz", + "integrity": "sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-sanitize": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-cjk-friendly": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/remark-cjk-friendly/-/remark-cjk-friendly-1.2.3.tgz", + "integrity": "sha512-UvAgxwlNk+l9Oqgl/9MWK2eWRS7zgBW/nXX9AthV7nd/3lNejF138E7Xbmk9Zs4WjTJGs721r7fAEc7tNFoH7g==", + "license": "MIT", + "dependencies": { + "micromark-extension-cjk-friendly": "1.2.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@types/mdast": "^4.0.0", + "unified": "^11.0.0" + }, + "peerDependenciesMeta": { + "@types/mdast": { + "optional": true + } + } + }, + "node_modules/remark-cjk-friendly-gfm-strikethrough": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/remark-cjk-friendly-gfm-strikethrough/-/remark-cjk-friendly-gfm-strikethrough-1.2.3.tgz", + "integrity": "sha512-bXfMZtsaomK6ysNN/UGRIcasQAYkC10NtPmP0oOHOV8YOhA2TXmwRXCku4qOzjIFxAPfish5+XS0eIug2PzNZA==", + "license": "MIT", + "dependencies": { + "micromark-extension-cjk-friendly-gfm-strikethrough": "1.2.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@types/mdast": "^4.0.0", + "unified": "^11.0.0" + }, + "peerDependenciesMeta": { + "@types/mdast": { + "optional": true + } + } + }, "node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmmirror.com/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -7911,25 +10949,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/remend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/remend/-/remend-1.0.1.tgz", + "integrity": "sha512-152puVH0qMoRJQFnaMG+rVDdf01Jq/CaED+MBuXExurJgdbkLp0c3TIe4R12o28Klx8uyGsjvFNG05aFG69G9w==", + "license": "Apache-2.0" }, "node_modules/resolve-from": { "version": "4.0.0", @@ -7941,16 +10965,6 @@ "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/robust-predicates": { "version": "3.0.3", "resolved": "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.3.tgz", @@ -8067,35 +11081,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmmirror.com/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", "license": "BSD-3-Clause" }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -8141,6 +11153,22 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/engine-javascript": "3.23.0", + "@shikijs/engine-oniguruma": "3.23.0", + "@shikijs/langs": "3.23.0", + "@shikijs/themes": "3.23.0", + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -8191,6 +11219,49 @@ "dev": true, "license": "MIT" }, + "node_modules/streamdown": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/streamdown/-/streamdown-1.6.11.tgz", + "integrity": "sha512-Y38fwRx5kCKTluwM+Gf27jbbi9q6Qy+WC9YrC1YbCpMkktT3PsRBJHMWiqYeF8y/JzLpB1IzDoeaB6qkQEDnAA==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1", + "hast": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.3.6", + "html-url-attributes": "^3.0.1", + "katex": "^0.16.22", + "lucide-react": "^0.542.0", + "marked": "^16.2.1", + "mermaid": "^11.11.0", + "rehype-harden": "^1.1.6", + "rehype-katex": "^7.0.1", + "rehype-raw": "^7.0.0", + "rehype-sanitize": "^6.0.0", + "remark-cjk-friendly": "^1.2.3", + "remark-cjk-friendly-gfm-strikethrough": "^1.2.3", + "remark-gfm": "^4.0.1", + "remark-math": "^6.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.2", + "remend": "1.0.1", + "shiki": "^3.12.2", + "tailwind-merge": "^3.3.1", + "unified": "^11.0.5", + "unist-util-visit": "^5.0.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/streamdown/node_modules/lucide-react": { + "version": "0.542.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.542.0.tgz", + "integrity": "sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -8282,33 +11353,10 @@ "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", "license": "MIT" }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -8317,18 +11365,6 @@ "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/tailwind-merge": { "version": "3.5.0", "resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.5.0.tgz", @@ -8340,41 +11376,10 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "license": "MIT" }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -8385,38 +11390,17 @@ "tailwindcss": ">=3.0.0 || insiders" } }, - "node_modules/tailwindcss/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" + "node": ">=6" }, - "engines": { - "node": ">=0.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/tinybench": { @@ -8439,6 +11423,7 @@ "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -8455,6 +11440,7 @@ "version": "6.5.0", "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -8472,6 +11458,7 @@ "version": "4.0.4", "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8490,17 +11477,11 @@ "node": ">=14.0.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/trim-lines": { "version": "3.0.1", @@ -8544,18 +11525,21 @@ "node": ">=6.10" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmmirror.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "license": "Apache-2.0" - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", @@ -8653,6 +11637,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-generated": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", + "integrity": "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-is": { "version": "6.0.1", "resolved": "https://registry.npmmirror.com/unist-util-is/-/unist-util-is-6.0.1.tgz", @@ -8735,6 +11729,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/untruncate-json": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/untruncate-json/-/untruncate-json-0.0.1.tgz", + "integrity": "sha512-4W9enDK4X1y1s2S/Rz7ysw6kDuMS3VmRjMFg7GZrNO+98OSe+x5Lh7PKYoVjy3lW/1wmhs6HW0lusnQRHgMarA==", + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -8776,6 +11776,20 @@ "punycode": "^2.1.0" } }, + "node_modules/urql": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/urql/-/urql-4.2.2.tgz", + "integrity": "sha512-3GgqNa6iF7bC4hY/ImJKN4REQILcSU9VKcKL8gfELZM8mM5BnLH1BsCc8kBdnVGD1LIFOs4W3O2idNHhON1r0w==", + "license": "MIT", + "dependencies": { + "@urql/core": "^5.1.1", + "wonka": "^6.3.2" + }, + "peerDependencies": { + "@urql/core": "^5.0.0", + "react": ">= 16.8.0" + } + }, "node_modules/use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmmirror.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -8819,6 +11833,21 @@ } } }, + "node_modules/use-stick-to-bottom": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/use-stick-to-bottom/-/use-stick-to-bottom-1.1.6.tgz", + "integrity": "sha512-z3Up8jYQGTkUCsGBnwg6/wj70KgXoW5Kz1AAc1j8MtQuYMBo6ZsdhrIXoegxa7gaMMilgQYyTohTrt3p94jHog==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/samdenty" + } + ], + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", @@ -8847,6 +11876,24 @@ "uuid": "dist-node/bin/uuid" } }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmmirror.com/vfile/-/vfile-6.0.3.tgz", @@ -9099,6 +12146,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", @@ -9132,6 +12195,12 @@ "node": ">=8" } }, + "node_modules/wonka": { + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.6.tgz", + "integrity": "sha512-MXH+6mDHAZ2GuMpgKS055FR6v0xVP3XwquxIMYXgiW+FejHQlMGlvVRZT4qMCxR+bEo/FCtIdKxwej9WV3YQag==", + "license": "MIT" + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", @@ -9249,15 +12318,23 @@ } }, "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmmirror.com/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "dev": true, + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, "node_modules/zod-validation-error": { "version": "4.0.2", "resolved": "https://registry.npmmirror.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz", diff --git a/package.json b/package.json index 7a6722b..2f1aa22 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "preview": "vite preview", "test": "vitest run src", "test:watch": "vitest src", + "test:e2e:agui": "playwright test --config playwright.agui.config.mjs", "build:ksadk": "VITE_BASE_PATH=./ vite build --outDir dist-ksadk" }, "exports": { @@ -57,6 +58,7 @@ "react-dom": "^19.2.4" }, "dependencies": { + "@ag-ui/client": "0.0.57", "@codemirror/autocomplete": "^6.20.2", "@codemirror/commands": "^6.10.3", "@codemirror/language": "^6.12.3", @@ -65,6 +67,8 @@ "@codemirror/state": "^6.6.0", "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.43.0", + "@copilotkit/a2ui-renderer": "^1.63.1", + "@copilotkit/react-core": "^1.63.1", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-dialog": "^1.1.15", @@ -73,7 +77,8 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", - "@tailwindcss/typography": "^0.5.19", + "@tailwindcss/postcss": "^4.3.3", + "@tailwindcss/typography": "^0.5.20", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", "class-variance-authority": "^0.7.1", @@ -92,10 +97,12 @@ "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", "uuid": "^13.0.0", + "zod": "^4.4.3", "zustand": "^5.0.13" }, "devDependencies": { "@eslint/js": "^9.39.4", + "@playwright/test": "^1.61.1", "@types/katex": "^0.16.8", "@types/node": "^24.12.0", "@types/react": "^19.2.14", @@ -112,7 +119,7 @@ "react": "^19.2.4", "react-dom": "^19.2.4", "rollup-plugin-visualizer": "^7.0.1", - "tailwindcss": "^3.4.3", + "tailwindcss": "^4.3.3", "typescript": "~5.9.3", "typescript-eslint": "^8.57.0", "vite": "^8.0.1", diff --git a/postcss.config.js b/postcss.config.js index 2e7af2b..14502dc 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,6 @@ export default { plugins: { - tailwindcss: {}, + "@tailwindcss/postcss": {}, autoprefixer: {}, }, } diff --git a/src/App.tsx b/src/App.tsx index 1d37ebe..f5325f5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -134,7 +134,14 @@ export function AgentWorkbench({ apiAdapter, initialSurface = 'chat', routeShell const selectedModelMetadata = availableModels.find((model) => model.id === selectedModel) || null; - const { submitDraft, stopGeneration, disconnectRun, resumeCheckpoint } = useRunAgent({ + const { + submitDraft, + stopGeneration, + disconnectRun, + resumeCheckpoint, + submitAguiAction, + respondToAguiApproval, + } = useRunAgent({ agentId, currentSessionId, agentFramework, @@ -358,6 +365,8 @@ export function AgentWorkbench({ apiAdapter, initialSurface = 'chat', routeShell onDeleteFeedback={deleteResponseFeedback} onSubmitFeedback={submitResponseFeedback} onRespondToApproval={respondToApproval} + onRespondToAguiApproval={respondToAguiApproval} + onSubmitAguiAction={submitAguiAction} onStopGeneration={handleStopGeneration} onCancelRemote={uiCapabilities.StopRun ? handleCancelRemote : undefined} checkpointResumeEnabled={ diff --git a/src/__tests__/agui-run-client.test.ts b/src/__tests__/agui-run-client.test.ts new file mode 100644 index 0000000..708ccd1 --- /dev/null +++ b/src/__tests__/agui-run-client.test.ts @@ -0,0 +1,196 @@ +import { describe, expect, it, vi } from 'vitest'; +import { AguiRunClient } from '../core/run/agui.js'; +import type { RunEvent } from '../core/run/types.js'; + +function sse(events: Array>): Response { + const body = events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join(''); + return new Response(body, { + status: 200, + headers: { 'content-type': 'text/event-stream' }, + }); +} + +describe('AguiRunClient', () => { + it('uses HttpAgent and projects official text, tool, reasoning, and activity events', async () => { + const calls: Array<{ url: string; body: Record }> = []; + const fetchMock = vi.fn(async (url: string, init: RequestInit) => { + calls.push({ url, body: JSON.parse(String(init.body)) as Record }); + return sse([ + { type: 'RUN_STARTED', threadId: 'session-1', runId: 'run-1' }, + { type: 'REASONING_MESSAGE_CONTENT', messageId: 'reasoning-1', delta: 'plan' }, + { type: 'TEXT_MESSAGE_START', messageId: 'message-1', role: 'assistant' }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: 'message-1', delta: 'hello' }, + { type: 'TOOL_CALL_START', toolCallId: 'tool-1', toolCallName: 'lookup' }, + { type: 'TOOL_CALL_ARGS', toolCallId: 'tool-1', delta: '{"q":"x"}' }, + { type: 'TOOL_CALL_END', toolCallId: 'tool-1' }, + { type: 'TOOL_CALL_RESULT', messageId: 'tool-result-1', toolCallId: 'tool-1', content: 'ok', role: 'tool' }, + { + type: 'ACTIVITY_SNAPSHOT', + messageId: 'surface-1', + activityType: 'a2ui-surface', + content: { + surfaceId: 'surface-1', + a2ui_operations: [ + { createSurface: { surfaceId: 'surface-1' } }, + { + updateComponents: { + surfaceId: 'surface-1', + components: [{ id: 'surface-1-root', component: 'Column', children: [] }], + }, + }, + ], + }, + }, + { type: 'TEXT_MESSAGE_END', messageId: 'message-1' }, + { type: 'RUN_FINISHED', threadId: 'session-1', runId: 'run-1', outcome: { type: 'success' } }, + ]); + }); + const projected: RunEvent[] = []; + const client = new AguiRunClient({ + url: '/agentengine/agui', + agentId: 'agent-1', + threadId: 'session-1', + fetch: fetchMock, + onEvent: (event) => projected.push(event), + }); + + const result = await client.run('hello', 'run-1'); + + expect(result.status).toBe('completed'); + expect(calls).toHaveLength(1); + expect(calls[0].url).toBe('/agentengine/agui'); + expect(calls[0].body).toMatchObject({ + threadId: 'session-1', + runId: 'run-1', + forwardedProps: { injectA2UITool: true }, + }); + expect(projected).toContainEqual({ type: 'text_delta', messageId: 'message-1', delta: 'hello' }); + expect(projected).toContainEqual({ type: 'reasoning_delta', messageId: 'reasoning-1', delta: 'plan' }); + expect(projected).toContainEqual({ type: 'tool_result', messageId: 'message-1', name: 'lookup', output: 'ok' }); + expect(projected).toContainEqual({ + type: 'agui_activity', + messageId: 'message-1', + surfaceId: 'surface-1', + messages: [ + { createSurface: { surfaceId: 'surface-1' } }, + { + updateComponents: { + surfaceId: 'surface-1', + components: [{ id: 'root', component: 'Column', children: [] }], + }, + }, + ], + }); + }); + + it('builds the official resume array for the pending interrupt', async () => { + const requestBodies: Array> = []; + const projected: RunEvent[] = []; + const responses = [ + sse([ + { type: 'RUN_STARTED', threadId: 'session-1', runId: 'run-1' }, + { + type: 'RUN_FINISHED', + threadId: 'session-1', + runId: 'run-1', + outcome: { + type: 'interrupt', + interrupts: [{ + id: 'approval-1', + reason: 'approval', + message: 'Approve writing the file?', + toolCallId: 'tool-1', + metadata: { + tool_name: 'write_file', + arguments: { path: '/tmp/x.txt' }, + approval_level: 'elevated', + }, + }], + }, + }, + ]), + sse([ + { type: 'RUN_STARTED', threadId: 'session-1', runId: 'run-2' }, + { type: 'RUN_FINISHED', threadId: 'session-1', runId: 'run-2', outcome: { type: 'success' } }, + ]), + ]; + const fetchMock = vi.fn(async (_url: string, init: RequestInit) => { + requestBodies.push(JSON.parse(String(init.body)) as Record); + return responses.shift()!; + }); + const client = new AguiRunClient({ + url: '/agentengine/agui', + agentId: 'agent-1', + threadId: 'session-1', + fetch: fetchMock, + onEvent: (event) => projected.push(event), + }); + + expect((await client.run('run command', 'run-1')).status).toBe('interrupted'); + expect(projected).toContainEqual({ + type: 'approval_requested', + messageId: 'run-1:assistant', + approvalRequestId: 'approval-1', + protocol: 'ag-ui', + name: 'write_file', + args: '{\n "path": "/tmp/x.txt"\n}', + message: 'Approve writing the file?', + approvalLevel: 'elevated', + }); + expect((await client.resume('run-2', { + interruptId: 'approval-1', + status: 'resolved', + payload: { decision: 'approve' }, + })).status).toBe('completed'); + + expect(requestBodies[1]).toMatchObject({ + threadId: 'session-1', + runId: 'run-2', + resume: [{ + interruptId: 'approval-1', + status: 'resolved', + payload: { decision: 'approve' }, + }], + }); + expect(requestBodies[0].context).toEqual(expect.arrayContaining([ + expect.objectContaining({ + description: expect.stringContaining('A2UI Component Schema'), + value: expect.stringContaining('https://a2ui.org/specification/v0_9/basic_catalog.json'), + }), + ])); + }); + + it('resumes a durable interrupt after the page is rehydrated', async () => { + const requestBodies: Array> = []; + const fetchMock = vi.fn(async (_url: string, init: RequestInit) => { + requestBodies.push(JSON.parse(String(init.body)) as Record); + return sse([ + { type: 'RUN_STARTED', threadId: 'session-1', runId: 'run-resume' }, + { type: 'RUN_FINISHED', threadId: 'session-1', runId: 'run-resume', outcome: { type: 'success' } }, + ]); + }); + const client = new AguiRunClient({ + url: '/agentengine/agui', + agentId: 'agent-1', + threadId: 'session-1', + fetch: fetchMock, + onEvent: () => {}, + }); + + await expect(client.resume('run-resume', { + interruptId: 'approval-durable-1', + status: 'resolved', + payload: { decision: 'approve' }, + })).resolves.toMatchObject({ status: 'completed' }); + + expect(requestBodies[0]).toMatchObject({ + threadId: 'session-1', + runId: 'run-resume', + resume: [{ + interruptId: 'approval-durable-1', + status: 'resolved', + payload: { decision: 'approve' }, + }], + }); + }); +}); diff --git a/src/__tests__/agui-transport.test.ts b/src/__tests__/agui-transport.test.ts new file mode 100644 index 0000000..b63e606 --- /dev/null +++ b/src/__tests__/agui-transport.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from 'vitest'; +import { + normalizeCapabilities, + resolveHostedChatTransport, +} from '../utils/capabilities.js'; + +const responses = { + Protocol: 'responses', + Runtime: 'ksadk', + Endpoint: '/v1/responses', + Version: 'v1', + Capabilities: { A2UI: false, Interrupt: true, Cancel: true }, +}; + +const agui = { + Protocol: 'ag-ui', + Runtime: 'copilotkit', + Endpoint: '/agentengine/agui', + Version: '0.1.19', + Capabilities: { A2UI: true, Interrupt: true, Cancel: true }, +}; + +describe('HostedChat transport selection', () => { + it('selects advertised AG-UI without guessing from framework', () => { + const capabilities = normalizeCapabilities({ + Data: { + Agent: { Framework: 'custom-framework' }, + HostedChat: { PreferredTransport: 'ag-ui', Transports: [agui, responses] }, + Capabilities: { HostedChat: { Enabled: true } }, + }, + }); + + expect(resolveHostedChatTransport(capabilities)).toMatchObject(agui); + }); + + it('falls back to Responses when AG-UI is absent or malformed', () => { + const capabilities = normalizeCapabilities({ + Data: { + HostedChat: { + PreferredTransport: 'ag-ui', + Transports: [{ ...agui, Endpoint: 'not-an-app-path' }, responses], + }, + Capabilities: { HostedChat: { Enabled: true } }, + }, + }); + + expect(resolveHostedChatTransport(capabilities)).toMatchObject(responses); + }); + + it('keeps legacy bootstrap responses-compatible', () => { + const capabilities = normalizeCapabilities({ + Data: { Agent: { Framework: 'langgraph' }, Capabilities: {} }, + }); + + expect(resolveHostedChatTransport(capabilities)).toMatchObject({ + Protocol: 'responses', + Endpoint: '/v1/responses', + }); + }); +}); diff --git a/src/__tests__/chat-message-list-contract.test.ts b/src/__tests__/chat-message-list-contract.test.ts index afaf540..0b7a197 100644 --- a/src/__tests__/chat-message-list-contract.test.ts +++ b/src/__tests__/chat-message-list-contract.test.ts @@ -77,11 +77,20 @@ describe('chat message list contracts', () => { expect(source).toContain('group-open/details:rotate-180'); expect(source).toContain('max-h-[min(46vh,28rem)]'); expect(source).toContain('custom-scrollbar'); - expect(source).toContain('border-emerald-200/70'); + expect(source).toContain('border-slate-200/80'); expect(source).toContain('生成中'); expect(source).toContain('leading-7'); }); + it('remeasures virtual rows when expandable content changes height', () => { + const source = readFileSync(resolve(repoRoot, 'src/components/chat/ChatMessageList.tsx'), 'utf8'); + + expect(source).toContain('new ResizeObserver(measure)'); + expect(source).toContain('observer.observe(node)'); + expect(source).toContain('observer.disconnect()'); + expect(source).toContain('scroller.scrollTop += height - previousHeight'); + }); + it('virtualizes long message transcripts instead of mapping the full list directly', () => { const source = readFileSync(resolve(repoRoot, 'src/components/chat/ChatMessageList.tsx'), 'utf8'); @@ -192,4 +201,14 @@ describe('chat message list contracts', () => { // run 结束后 shouldReloadSession 重新 loadSession 拿最终消息。 expect(lifecycleSource).toContain('重连期间不覆盖消息列表'); }); + + it('keeps an initial transcript load distinct from an actually empty session', () => { + const connectedSource = readFileSync(resolve(repoRoot, 'src/components/chat/ConnectedMessageList.tsx'), 'utf8'); + const listSource = readFileSync(resolve(repoRoot, 'src/components/chat/ChatMessageList.tsx'), 'utf8'); + + expect(connectedSource).toContain('isLoadingSessions'); + expect(connectedSource).toContain('isLoadingInitialHistory'); + expect(listSource).toContain('InitialHistorySkeleton'); + expect(listSource).toContain('messages.length === 0 && isLoadingInitialHistory'); + }); }); diff --git a/src/__tests__/messages-mapper.test.ts b/src/__tests__/messages-mapper.test.ts index 08f327b..9676657 100644 --- a/src/__tests__/messages-mapper.test.ts +++ b/src/__tests__/messages-mapper.test.ts @@ -75,6 +75,31 @@ describe('mapBackendMessage', () => { expect(result.tools.send_email.status).toBe('paused'); expect(result.tools.send_email.approvalRequestId).toBe('apr-1'); expect(result.tools.send_email.approvalStatus).toBe('pending'); + expect(result.tools.send_email.approvalProtocol).toBe('responses'); + }); + + it('preserves AG-UI protocol for replayed approval events', () => { + const msg = { + Role: 'assistant', + Content: { text: '' }, + ToolEvents: [ + { + Name: 'run_command', + Status: 'approved', + ApprovalRequestId: 'interrupt-1', + Protocol: 'ag-ui', + ApprovalLevel: 'elevated', + ApprovalMessage: '运行此高风险命令前需要确认。', + }, + ], + } as BackendMessage; + + const result = mapBackendMessage(msg); + + expect(result.tools.run_command.approvalStatus).toBe('approved'); + expect(result.tools.run_command.approvalProtocol).toBe('ag-ui'); + expect(result.tools.run_command.approvalLevel).toBe('elevated'); + expect(result.tools.run_command.approvalMessage).toBe('运行此高风险命令前需要确认。'); }); it('maps denied approval to rejected', () => { @@ -97,4 +122,49 @@ describe('mapBackendMessage', () => { expect(result[0].role).toBe('user'); expect(result[1].role).toBe('model'); }); + + it('rehydrates persisted A2UI operations as an activity message', () => { + const result = mapBackendMessages([{ + MessageId: 'assistant-1', + Role: 'assistant', + Content: { text: '状态如下' }, + Activities: [{ + MessageId: 'run-1:a2ui:status', + SurfaceId: 'status', + Content: { + a2ui_operations: [{ createSurface: { surfaceId: 'status' } }], + }, + }], + }]); + + expect(result).toHaveLength(2); + expect(result[1]).toMatchObject({ + role: 'a2ui', + aguiActivity: { + surfaceId: 'status', + messages: [{ createSurface: { surfaceId: 'status' } }], + }, + }); + }); + + it('repairs only the legacy A2UI root id during history rehydration', () => { + const result = mapBackendMessages([{ + MessageId: 'assistant-legacy', + Role: 'assistant', + Content: { text: '状态如下' }, + Activities: [{ + SurfaceId: 'status', + Content: { + a2ui_operations: [{ + updateComponents: { + surfaceId: 'status', + components: [{ id: 'status-root', component: 'Column', children: [] }], + }, + }], + }, + }], + }]); + + expect(result[1].aguiActivity.messages[0].updateComponents.components[0].id).toBe('root'); + }); }); diff --git a/src/__tests__/run-engine.test.ts b/src/__tests__/run-engine.test.ts index ef9fd02..7a530d8 100644 --- a/src/__tests__/run-engine.test.ts +++ b/src/__tests__/run-engine.test.ts @@ -97,6 +97,191 @@ describe('RunEngineImpl', () => { useSessionStore.getState().setCurrentSessionId(null); useCheckpointStore.getState().clearSessionCheckpoints(); resetDispatcherState(); + vi.unstubAllGlobals(); + }); + + it('projects AG-UI approval resolution without reviving the pending card', () => { + useSessionStore.getState().setCurrentSessionId('session-1'); + + dispatchRunEventToStores({ + type: 'approval_requested', + sessionId: 'session-1', + messageId: 'message-1', + approvalRequestId: 'approval-1', + protocol: 'ag-ui', + name: 'write_file', + args: '{"path":"/tmp/x.txt"}', + message: 'Approve?', + }); + dispatchRunEventToStores({ + type: 'approval_resolved', + sessionId: 'session-1', + approvalRequestId: 'approval-1', + decision: 'approved', + }); + dispatchRunEventToStores({ + type: 'approval_requested', + sessionId: 'session-1', + messageId: 'message-1', + approvalRequestId: 'approval-1', + protocol: 'ag-ui', + name: 'write_file', + args: '{"path":"/tmp/x.txt"}', + message: 'Approve?', + }); + + expect(useMessageStore.getState().messages[0].tools?.['approval-1']).toMatchObject({ + approvalRequestId: 'approval-1', + approvalProtocol: 'ag-ui', + approvalStatus: 'approved', + status: 'completed', + }); + }); + + it('projects a live AG-UI approval into a fresh assistant row after a session switch', () => { + useSessionStore.getState().setCurrentSessionId('session-before'); + dispatchRunEventToStores({ + type: 'assistant_message_created', + sessionId: 'session-before', + messageId: 'assistant-before', + }); + + // Loading a different session clears the visible transcript but must not + // leave a module-level assistant marker that drops its first live event. + useMessageStore.getState().setMessages([]); + useSessionStore.getState().setCurrentSessionId('session-live'); + dispatchRunEventToStores({ + type: 'approval_requested', + sessionId: 'session-live', + messageId: 'assistant-live', + approvalRequestId: 'approval-live', + protocol: 'ag-ui', + name: 'run_command', + args: '{"command":"pwd"}', + message: 'Approval required', + }); + + expect(useMessageStore.getState().messages).toEqual([ + expect.objectContaining({ + id: 'assistant-live', + tools: { + 'approval-live': expect.objectContaining({ + approvalStatus: 'pending', + approvalProtocol: 'ag-ui', + }), + }, + }), + ]); + }); + + it('settles session streaming when AG-UI finishes with an approval interrupt', async () => { + const fetchMock = vi.fn(async () => new Response( + [ + 'data: {"type":"RUN_STARTED","threadId":"session-approval","runId":"run-approval"}', + '', + 'data: {"type":"RUN_FINISHED","threadId":"session-approval","runId":"run-approval","outcome":{"type":"interrupt","interrupts":[{"id":"approval-1","reason":"tool","message":"Approval required","toolCallId":"approval-1"}]}}', + '', + ].join('\n'), + { headers: { 'content-type': 'text/event-stream' } }, + )); + vi.stubGlobal('fetch', fetchMock); + useSessionStore.getState().setCurrentSessionId('session-approval'); + const engine = createRunEngine(createApiFacade([])); + engine.subscribe(dispatchRunEventToStores); + engine.updateConfig({ + agentId: 'agent-live', + apiFormats: ['responses'], + agentFramework: 'langgraph', + selectedModel: '', + thinkingMode: 'auto', + hostedChatTransport: { + Protocol: 'ag-ui', + Runtime: 'copilotkit', + Endpoint: '/agentengine/agui', + Version: '0.1.19', + Capabilities: { A2UI: true, Interrupt: true, Cancel: true }, + }, + }); + + expect(engine.start({ text: 'run command', attachments: [], sessionId: 'session-approval' })).toBe(true); + for (let attempt = 0; attempt < 20 && fetchMock.mock.calls.length === 0; attempt += 1) { + await new Promise((resolve) => setTimeout(resolve, 0)); + } + expect(fetchMock).toHaveBeenCalledOnce(); + await waitForEngineIdle(engine); + + expect(useStreamingStore.getState().getSessionActivity('session-approval')).toMatchObject({ + status: 'waiting', + phase: '等待人工确认', + }); + expect(useStreamingStore.getState().isSessionStreaming('session-approval')).toBe(false); + expect(useMessageStore.getState().messages[0].tools?.['approval-1']).toMatchObject({ + approvalStatus: 'pending', + approvalProtocol: 'ag-ui', + }); + }); + + it('resumes a rehydrated AG-UI approval through its durable session', async () => { + const fetchCalls: Array<{ url: string; body: Record }> = []; + vi.stubGlobal('fetch', vi.fn(async (url: string, init: RequestInit) => { + fetchCalls.push({ url, body: JSON.parse(String(init.body)) as Record }); + return new Response( + [ + 'data: {"type":"RUN_STARTED","threadId":"session-history","runId":"run-resume"}', + '', + 'data: {"type":"RUN_FINISHED","threadId":"session-history","runId":"run-resume","outcome":{"type":"success"}}', + '', + ].join('\n'), + { headers: { 'content-type': 'text/event-stream' } }, + ); + })); + const engine = createRunEngine(createApiFacade([])); + const resolved: string[] = []; + engine.subscribe((event) => { + if (event.type === 'approval_resolved') resolved.push(event.approvalRequestId); + }); + engine.updateConfig({ + agentId: 'agent-live', + apiFormats: ['responses'], + agentFramework: 'langgraph', + selectedModel: '', + thinkingMode: 'auto', + hostedChatTransport: { + Protocol: 'ag-ui', + Runtime: 'copilotkit', + Endpoint: '/agentengine/agui', + Version: '0.1.19', + Capabilities: { A2UI: true, Interrupt: true, Cancel: true }, + }, + }); + + const accepted = engine.resumeAguiInterrupt({ + sessionId: 'session-history', + interruptId: 'approval-history-1', + status: 'resolved', + payload: { decision: 'approve' }, + }); + + expect(accepted).toBe(true); + for (let attempt = 0; attempt < 20 && fetchCalls.length === 0; attempt += 1) { + await new Promise((resolve) => setTimeout(resolve, 0)); + } + await waitForEngineIdle(engine); + + expect(fetchCalls).toEqual([ + expect.objectContaining({ + url: '/agentengine/agui', + body: expect.objectContaining({ + threadId: 'session-history', + resume: [{ + interruptId: 'approval-history-1', + status: 'resolved', + payload: { decision: 'approve' }, + }], + }), + }), + ]); + expect(resolved).toEqual(['approval-history-1']); }); it('uses the latest runtime config when starting a run', async () => { diff --git a/src/__tests__/session-message-history-store.test.ts b/src/__tests__/session-message-history-store.test.ts index 83450b1..64c1673 100644 --- a/src/__tests__/session-message-history-store.test.ts +++ b/src/__tests__/session-message-history-store.test.ts @@ -14,17 +14,21 @@ describe('session message history state', () => { store.setSessionMessageHistoryLoading('session-a', true); expect(useSessionStore.getState().messageHistory).toEqual({ - 'session-a': { nextCursor: 8, hasMore: true, isLoadingOlder: true }, - 'session-b': { nextCursor: null, hasMore: false, isLoadingOlder: false }, + 'session-a': { nextCursor: 8, hasMore: true, isLoadingInitial: false, isLoadingOlder: true }, + 'session-b': { nextCursor: null, hasMore: false, isLoadingInitial: false, isLoadingOlder: false }, }); store.clearSessionMessageHistory('session-a'); expect(useSessionStore.getState().messageHistory).toEqual({ - 'session-b': { nextCursor: null, hasMore: false, isLoadingOlder: false }, + 'session-b': { nextCursor: null, hasMore: false, isLoadingInitial: false, isLoadingOlder: false }, }); }); + it('starts in restoring mode so the first paint cannot claim an empty session', () => { + expect(useSessionStore.getState().isLoadingSessions).toBe(true); + }); + it('rejects stale older-message scroll work after session or request changes', () => { const requestToken = Symbol('request-a'); @@ -47,4 +51,21 @@ describe('session message history state', () => { activeRequestToken: Symbol('replacement'), })).toBe(false); }); + + it('tracks initial history loading independently from loading older pages', () => { + const store = useSessionStore.getState(); + + store.setSessionInitialMessageHistoryLoading('session-a', true); + + expect(useSessionStore.getState().messageHistory['session-a']).toEqual({ + nextCursor: null, + hasMore: false, + isLoadingOlder: false, + isLoadingInitial: true, + }); + + store.setSessionMessageHistory('session-a', { nextCursor: null, hasMore: false }); + + expect(useSessionStore.getState().messageHistory['session-a']?.isLoadingInitial).toBe(false); + }); }); diff --git a/src/__tests__/streaming-store.test.ts b/src/__tests__/streaming-store.test.ts index fa93673..20eb279 100644 --- a/src/__tests__/streaming-store.test.ts +++ b/src/__tests__/streaming-store.test.ts @@ -15,6 +15,7 @@ describe('streaming store session activity', () => { status: 'running', phase: '后台长任务运行中', }); + store.setSessionStreaming('session-1', true); useStreamingStore.getState().stopActivity('用户停止接收'); @@ -25,4 +26,22 @@ describe('streaming store session activity', () => { expect(useStreamingStore.getState().isSessionStreaming('session-1')).toBe(false); expect(useStreamingStore.getState().getSessionActivity('session-1')?.status).toBe('stopped'); }); + + it('keeps a pending approval visible after its transport stream settles', () => { + const store = useStreamingStore.getState(); + store.updateActivity({ + sessionId: 'session-approval', + status: 'waiting', + phase: '等待人工确认', + }); + store.setSessionStreaming('session-approval', true); + + store.setSessionStreaming('session-approval', false); + + expect(store.getSessionActivity('session-approval')).toMatchObject({ + status: 'waiting', + phase: '等待人工确认', + }); + expect(store.isSessionStreaming('session-approval')).toBe(false); + }); }); diff --git a/src/api/messages.ts b/src/api/messages.ts index bb8e5f6..3b1ad9b 100644 --- a/src/api/messages.ts +++ b/src/api/messages.ts @@ -14,9 +14,19 @@ export type BackendMessage = { Status?: 'running' | 'completed' | 'failed' | 'paused' | 'approved' | 'denied'; ToolCallId?: string; ApprovalRequestId?: string; + Protocol?: string; + ApprovalLevel?: string; + ApprovalMessage?: string; ResultSeqId?: number; Reason?: string; }[]; + Activities?: { + SeqId?: number; + Type?: string; + MessageId?: string; + SurfaceId?: string; + Content?: unknown; + }[]; Attachments?: { file_uri: string; name: string; diff --git a/src/components/chat/A2UIActivityMessage.tsx b/src/components/chat/A2UIActivityMessage.tsx new file mode 100644 index 0000000..6c19639 --- /dev/null +++ b/src/components/chat/A2UIActivityMessage.tsx @@ -0,0 +1,49 @@ +import { useEffect } from 'react'; +import { + A2UIProvider, + A2UIRenderer, + useA2UI, + type A2UIClientEventMessage, +} from '@copilotkit/a2ui-renderer'; +import { ksadkA2uiCatalog } from '../../core/run/a2ui.js'; + +function ActivitySurface({ + surfaceId, + messages, +}: { + surfaceId: string; + messages: Array>; +}) { + const { processMessages } = useA2UI(); + + useEffect(() => { + processMessages(messages); + }, [messages, processMessages]); + + return ( + 界面内容暂不可用} + loadingFallback={
正在加载界面
} + /> + ); +} + +export function A2UIActivityMessage({ + surfaceId, + messages, + onAction, +}: { + surfaceId: string; + messages: Array>; + onAction?: (message: A2UIClientEventMessage) => void; +}) { + return ( +
+ + + +
+ ); +} diff --git a/src/components/chat/ChatMessageList.tsx b/src/components/chat/ChatMessageList.tsx index c74b333..b7ba952 100644 --- a/src/components/chat/ChatMessageList.tsx +++ b/src/components/chat/ChatMessageList.tsx @@ -1,4 +1,13 @@ -import { useEffect, useLayoutEffect, useMemo, useState, type RefObject } from 'react'; +import { + useCallback, + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState, + type ReactNode, + type RefObject, +} from 'react'; import { Bot, @@ -27,6 +36,8 @@ import { calculateVirtualMessageWindow } from '../../utils/message-virtualizatio import type { RunActivity } from '../../stores/streaming.js'; import type { SessionCheckpoint } from '../../stores/checkpoint.js'; import type { ComposerContextIndicator, Message, MessageAttachment } from './types'; +import type { A2UIClientEventMessage } from '@copilotkit/a2ui-renderer'; +import { A2UIActivityMessage } from './A2UIActivityMessage'; type ChatMessageListProps = { agentName: string; @@ -35,12 +46,15 @@ type ChatMessageListProps = { activity: RunActivity | null; contextIndicator: ComposerContextIndicator; messages: Message[]; + isLoadingInitialHistory?: boolean; onOpenAttachmentPreview: (attachment: MessageAttachment) => void; onRespondToApproval: (options: { approvalRequestId: string; approve: boolean; previousResponseId?: string; }) => void; + onRespondToAguiApproval?: (options: { interruptId: string; approve: boolean }) => void; + onSubmitAguiAction?: (message: A2UIClientEventMessage) => void; onSubmitFeedback: (options: { message: Message; rating: 'up' | 'down'; @@ -57,6 +71,55 @@ type ChatMessageListProps = { const DEFAULT_MESSAGE_ROW_HEIGHT = 140; const MESSAGE_VIRTUALIZATION_OVERSCAN = 4; +function approvalLevelLabel(level?: string) { + const normalized = String(level || '').trim().toLowerCase(); + if (normalized === 'elevated') return '高风险'; + if (normalized === 'always') return '始终确认'; + if (normalized === 'confirm') return '需确认'; + return level || ''; +} + +function approvalLevelTone(level?: string) { + const normalized = String(level || '').trim().toLowerCase(); + return normalized === 'elevated' + ? 'border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-900/70 dark:bg-rose-950/30 dark:text-rose-200' + : 'border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-900/70 dark:bg-amber-950/30 dark:text-amber-200'; +} + +function MeasuredMessageRow({ + messageId, + top, + onMeasure, + children, +}: { + messageId: string; + top: number; + onMeasure: (messageId: string, height: number, top: number) => void; + children: ReactNode; +}) { + const rowRef = useRef(null); + + useLayoutEffect(() => { + const node = rowRef.current; + if (!node) return undefined; + const measure = () => onMeasure(messageId, node.offsetHeight, top); + measure(); + if (typeof ResizeObserver === 'undefined') return undefined; + const observer = new ResizeObserver(measure); + observer.observe(node); + return () => observer.disconnect(); + }, [messageId, onMeasure, top]); + + return ( +
+ {children} +
+ ); +} + function formatElapsed(ms: number) { const safe = Math.max(0, Math.floor(ms / 1000)); const minutes = Math.floor(safe / 60); @@ -85,11 +148,6 @@ function AnimatedTokenCount({ contextIndicator }: { contextIndicator: ComposerCo const contextWindowTokens = contextIndicator?.contextWindowTokens; const label = formatCompactTokens(usedTokens); const windowLabel = formatCompactTokens(contextWindowTokens); - const [pulseKey, setPulseKey] = useState(0); - - useEffect(() => { - if (label) setPulseKey((current) => current + 1); - }, [label]); if (!label) return null; @@ -97,7 +155,7 @@ function AnimatedTokenCount({ contextIndicator }: { contextIndicator: ComposerCo const title = contextIndicator?.label || `估算 token ${detail}`; return ( @@ -204,6 +262,17 @@ function EmptyState({ agentName }: { agentName: string }) { ); } +function InitialHistorySkeleton() { + return ( +
+
+
+
+
+
+ ); +} + function formatCheckpointPhase(phase?: string) { const normalized = String(phase || '').trim(); if (!normalized) return '保存运行状态'; @@ -665,7 +734,9 @@ function ChatMessage({ onDeleteFeedback, onOpenAttachmentPreview, onRespondToApproval, + onRespondToAguiApproval, onSubmitFeedback, + onSubmitAguiAction, }: { agentName: string; isMobile: boolean; @@ -675,7 +746,9 @@ function ChatMessage({ onDeleteFeedback: (message: Message) => void; onOpenAttachmentPreview: (attachment: MessageAttachment) => void; onRespondToApproval: ChatMessageListProps['onRespondToApproval']; + onRespondToAguiApproval?: ChatMessageListProps['onRespondToAguiApproval']; onSubmitFeedback: ChatMessageListProps['onSubmitFeedback']; + onSubmitAguiAction?: ChatMessageListProps['onSubmitAguiAction']; }) { if (message.role === 'user') { return ( @@ -694,6 +767,16 @@ function ChatMessage({ ); } + if (message.role === 'a2ui' && message.aguiActivity) { + return ( + + ); + } + return (
@@ -710,22 +793,22 @@ function ChatMessage({ ) : null} {message.reasoning ? ( -
- +
+
{isStreaming && isLastMessage && !message.content ? ( - + ) : ( - + )} 思考过程 - + {isStreaming && isLastMessage && !message.content ? '生成中' : '已完成'}
-
+
@@ -737,30 +820,37 @@ function ChatMessage({ ? Object.values(message.tools).map((tool, toolIndex) => (
- +
{tool.status === 'running' ? ( - + ) : tool.status === 'paused' ? ( ) : tool.status === 'error' ? ( ) : ( - + )} - {tool.status === 'paused' + {tool.approvalStatus === 'pending' ? '等待审批:' + : tool.approvalStatus === 'approved' + ? '已批准:' + : tool.approvalStatus === 'rejected' + ? '已拒绝:' : tool.status === 'error' ? '工具调用失败:' : '工具调用:'} @@ -770,54 +860,89 @@ function ChatMessage({
- {tool.status === 'paused' && tool.approvalRequestId ? ( -
-
该工具调用需要人工确认后继续。
+ {tool.approvalRequestId ? ( +
+
+ {tool.approvalStatus === 'approved' + ? '已批准该工具调用。' + : tool.approvalStatus === 'rejected' + ? '已拒绝该工具调用。' + : tool.approvalMessage || '该工具调用需要人工确认后继续。'} +
+ {tool.approvalLevel ? ( +
+ 审批级别:{approvalLevelLabel(tool.approvalLevel)} +
+ ) : null} {tool.serverLabel ? (
MCP Server: {tool.serverLabel}
) : null} + {tool.approvalStatus === 'pending' ? (
+ ) : ( +
+ {tool.approvalStatus === 'approved' ? ( + + ) : ( + + )} + {tool.approvalStatus === 'approved' ? '已批准' : '已拒绝'} +
+ )}
) : null} {tool.args ? ( @@ -843,6 +968,15 @@ function ChatMessage({ ) : null}
+ {message.aguiActivities?.map((activity) => ( + + ))} + >(new Map()); + const measuredHeightsRef = useRef(measuredHeights); useLayoutEffect(() => { const scroller = scrollRef.current; @@ -911,19 +1049,24 @@ export function ChatMessageList({ const visibleItems = virtualWindow.visibleItems; - const updateMeasuredHeight = (messageId: string, height: number) => { + const updateMeasuredHeight = useCallback((messageId: string, height: number, top: number) => { if (!messageId || !Number.isFinite(height) || height <= 0) { return; } - setMeasuredHeights((current) => { - if (current.get(messageId) === height) { - return current; - } - const next = new Map(current); - next.set(messageId, height); - return next; - }); - }; + const current = measuredHeightsRef.current; + const previousHeight = current.get(messageId) ?? DEFAULT_MESSAGE_ROW_HEIGHT; + if (previousHeight === height) return; + const next = new Map(current); + next.set(messageId, height); + measuredHeightsRef.current = next; + setMeasuredHeights(next); + + const scroller = scrollRef.current; + if (scroller && top < scroller.scrollTop) { + scroller.scrollTop += height - previousHeight; + setScrollTop(scroller.scrollTop); + } + }, [scrollRef]); return (
- {messages.length === 0 ? ( + {messages.length === 0 && isLoadingInitialHistory ? ( + + ) : messages.length === 0 ? ( ) : (
{visibleItems.map((entry) => ( -
{ - if (!node) return; - updateMeasuredHeight(entry.item.id || String(entry.index), node.offsetHeight); - }} - style={{ - position: 'absolute', - top: entry.top, - left: 0, - right: 0, - }} + messageId={entry.item.id || String(entry.index)} + top={entry.top} + onMeasure={updateMeasuredHeight} > {entry.item.role === 'system' ? ( @@ -970,10 +1108,12 @@ export function ChatMessageList({ onDeleteFeedback={onDeleteFeedback} onOpenAttachmentPreview={onOpenAttachmentPreview} onRespondToApproval={onRespondToApproval} + onRespondToAguiApproval={onRespondToAguiApproval} onSubmitFeedback={onSubmitFeedback} + onSubmitAguiAction={onSubmitAguiAction} /> )} -
+ ))}
)} diff --git a/src/components/chat/ConnectedMessageList.tsx b/src/components/chat/ConnectedMessageList.tsx index d3deca3..12d1ba2 100644 --- a/src/components/chat/ConnectedMessageList.tsx +++ b/src/components/chat/ConnectedMessageList.tsx @@ -14,6 +14,7 @@ import type { ModelStore } from '../../stores/model.js'; import type { SessionStore } from '../../stores/session.js'; import type { StreamingStore } from '../../stores/streaming.js'; import type { UIStore } from '../../stores/ui.js'; +import type { A2UIClientEventMessage } from '@copilotkit/a2ui-renderer'; type ConnectedMessageListProps = { agentName: string; @@ -21,6 +22,8 @@ type ConnectedMessageListProps = { onDeleteFeedback: (message: Message) => void; onSubmitFeedback: (options: { message: Message; rating: 'up' | 'down'; comment?: string }) => void; onRespondToApproval: (options: { approvalRequestId: string; approve: boolean; previousResponseId?: string }) => void; + onRespondToAguiApproval?: (options: { interruptId: string; approve: boolean }) => void; + onSubmitAguiAction?: (message: A2UIClientEventMessage) => void; onStopGeneration?: () => void; onCancelRemote?: () => void; checkpointResumeEnabled?: boolean; @@ -34,6 +37,8 @@ export function ConnectedMessageList({ onDeleteFeedback, onSubmitFeedback, onRespondToApproval, + onRespondToAguiApproval, + onSubmitAguiAction, onStopGeneration, onCancelRemote, checkpointResumeEnabled = false, @@ -42,12 +47,14 @@ export function ConnectedMessageList({ }: ConnectedMessageListProps) { const messages = useMessageStore(s => s.messages); const currentSessionId = useSessionStore((s: SessionStore) => s.currentSessionId); + const isLoadingSessions = useSessionStore((s: SessionStore) => s.isLoadingSessions); const isStreaming = useStreamingStore((s: StreamingStore) => Boolean(s.getSessionActivity(currentSessionId) && s.isSessionStreaming(currentSessionId))); const activity = useStreamingStore((s: StreamingStore) => s.getSessionActivity(currentSessionId)); const checkpoints = useCheckpointStore(s => s.getSessionCheckpoints(currentSessionId)); const currentMessageHistory = useSessionStore((s: SessionStore) => currentSessionId ? s.messageHistory[currentSessionId] : null, ); + const isLoadingInitialHistory = isLoadingSessions || Boolean(currentMessageHistory?.isLoadingInitial); const input = useUIStore((s: UIStore) => s.input); const availableModels = useModelStore((s: ModelStore) => s.availableModels); const selectedModel = useModelStore((s: ModelStore) => s.selectedModel); @@ -259,10 +266,13 @@ export function ConnectedMessageList({ activity={activity} contextIndicator={contextIndicator} messages={messages} + isLoadingInitialHistory={isLoadingInitialHistory} onDeleteFeedback={onDeleteFeedback} onOpenAttachmentPreview={openAttachmentPreview} onRespondToApproval={onRespondToApproval} + onRespondToAguiApproval={onRespondToAguiApproval} onSubmitFeedback={onSubmitFeedback} + onSubmitAguiAction={onSubmitAguiAction} onStopGeneration={onStopGeneration} onCancelRemote={onCancelRemote} checkpoints={checkpointResumeEnabled ? checkpoints : []} diff --git a/src/components/chat/types.ts b/src/components/chat/types.ts index e2746bd..eb30fa9 100644 --- a/src/components/chat/types.ts +++ b/src/components/chat/types.ts @@ -12,7 +12,7 @@ export type PreviewImageSize = { export type Message = { id: string; - role: 'user' | 'model' | 'tool' | 'system'; + role: 'user' | 'model' | 'tool' | 'system' | 'a2ui'; content: string; timestamp: number; responseId?: string; @@ -26,6 +26,24 @@ export type Message = { compactedUntilSeqId?: number; historical?: boolean; reasoning?: string; + a2ui?: { + surfaceId: string; + surface: import('../../core/stream/types.js').A2UISurface; + pendingInteraction?: { + interactionId: string; + kind: string; + inputSchema: Record; + }; + ended?: boolean; + }; + aguiActivity?: { + surfaceId: string; + messages: Array>; + }; + aguiActivities?: Array<{ + surfaceId: string; + messages: Array>; + }>; tools?: { [name: string]: { name: string; @@ -36,6 +54,9 @@ export type Message = { previousResponseId?: string; serverLabel?: string; approvalStatus?: 'pending' | 'approved' | 'rejected'; + approvalProtocol?: 'responses' | 'ag-ui'; + approvalMessage?: string; + approvalLevel?: string; }; }; attachments?: MessageAttachment[]; diff --git a/src/core/run/a2ui.ts b/src/core/run/a2ui.ts new file mode 100644 index 0000000..feb56e7 --- /dev/null +++ b/src/core/run/a2ui.ts @@ -0,0 +1,56 @@ +import { + A2UI_SCHEMA_CONTEXT_DESCRIPTION, + basicCatalog, + buildCatalogContextValue, +} from '@copilotkit/a2ui-renderer'; + +// The agent currently emits the official v0.9 basic catalog id. Creating a +// second catalog that happens to contain the same components changes that id, +// which makes the renderer reject every createSurface operation. +export const ksadkA2uiCatalog = basicCatalog; + +export const ksadkA2uiAgentContext = { + description: A2UI_SCHEMA_CONTEXT_DESCRIPTION, + value: buildCatalogContextValue(ksadkA2uiCatalog), +}; + +/** + * CopilotKit's v0.9 React renderer always begins rendering at component id + * `root`. Early local A2UI events used a surface-specific `*-root` id and + * were persisted that way. Keep the repair deliberately narrow so a valid + * A2UI tree is never rewritten. + */ +export function normalizeA2uiOperations( + operations: Array>, +): Array> { + return operations.map((operation) => { + const update = operation.updateComponents; + if (!update || typeof update !== 'object' || Array.isArray(update)) return operation; + + const components = (update as Record).components; + if (!Array.isArray(components)) return operation; + + const componentRecords = components.filter( + (component): component is Record => Boolean( + component && typeof component === 'object' && !Array.isArray(component), + ), + ); + if (componentRecords.some((component) => component.id === 'root')) return operation; + + const legacyRoots = componentRecords.filter( + (component) => typeof component.id === 'string' && component.id.endsWith('-root'), + ); + if (legacyRoots.length !== 1) return operation; + + const legacyRoot = legacyRoots[0]; + return { + ...operation, + updateComponents: { + ...update, + components: components.map((component) => component === legacyRoot + ? { ...legacyRoot, id: 'root' } + : component), + }, + }; + }); +} diff --git a/src/core/run/agui.ts b/src/core/run/agui.ts new file mode 100644 index 0000000..6f7f99a --- /dev/null +++ b/src/core/run/agui.ts @@ -0,0 +1,257 @@ +import { + buildResumeArray, + HttpAgent, + type AgentSubscriber, + type RunAgentResult, +} from '@ag-ui/client'; +import type { BaseEvent, Interrupt } from '@ag-ui/core'; +import type { RunEvent } from './types.js'; +import { ksadkA2uiAgentContext, normalizeA2uiOperations } from './a2ui.js'; + +type AguiRunStatus = 'completed' | 'interrupted' | 'failed' | 'cancelled'; + +type AguiRunResult = { + status: AguiRunStatus; + result: RunAgentResult; +}; + +type AguiRunClientOptions = { + url: string; + agentId: string; + threadId: string; + onEvent: (event: RunEvent) => void; + fetch?: typeof fetch; +}; + +type ToolState = { name: string; args: string }; + +function eventType(event: BaseEvent): string { + return String((event as { type?: unknown }).type || '').toUpperCase(); +} + +function eventMessageId(event: BaseEvent, fallback: string): string { + return String((event as { messageId?: unknown }).messageId || fallback); +} + +function eventRunId(event: BaseEvent, fallback: string): string { + return String((event as { runId?: unknown }).runId || fallback); +} + +function asObject(value: unknown): Record { + return value && typeof value === 'object' && !Array.isArray(value) + ? value as Record + : {}; +} + +function activityMessages(content: unknown): Array> { + if (Array.isArray(content)) { + return normalizeA2uiOperations( + content.filter((item): item is Record => Boolean(item && typeof item === 'object')), + ); + } + if (content && typeof content === 'object') { + const operations = (content as Record).a2ui_operations; + if (Array.isArray(operations)) { + return normalizeA2uiOperations( + operations.filter((item): item is Record => Boolean(item && typeof item === 'object')), + ); + } + return [content as Record]; + } + return []; +} + +function stringifyPayload(value: unknown): string { + if (value === undefined || value === null || value === '') return ''; + if (typeof value === 'string') return value; + return JSON.stringify(value, null, 2); +} + +export class AguiRunClient { + private readonly agent: HttpAgent; + private readonly onEvent: (event: RunEvent) => void; + private readonly tools = new Map(); + private readonly runMessageIds = new Map(); + private readonly pendingByRun = new Map(); + private activeRunId = ''; + + constructor(options: AguiRunClientOptions) { + this.agent = new HttpAgent({ + url: options.url, + agentId: options.agentId, + threadId: options.threadId, + fetch: options.fetch, + }); + this.onEvent = options.onEvent; + } + + async run(text: string, runId: string, signal?: AbortSignal): Promise { + this.activeRunId = runId; + this.agent.addMessage({ + id: `${runId}:user`, + role: 'user', + content: text, + }); + return this.execute({ runId, abortController: this.controllerFor(signal) }); + } + + async resume( + runId: string, + response: { interruptId: string; status: 'resolved' | 'cancelled'; payload?: unknown }, + ): Promise { + const rememberedInterrupts = this.agent.pendingInterrupts.length > 0 + ? this.agent.pendingInterrupts + : this.pendingByRun.get(this.activeRunId) || []; + // A browser refresh drops HttpAgent's in-memory interrupt list. The server + // is still authoritative for its durable thread, so send the official + // resume shape for the persisted interrupt id instead of rejecting it. + const interrupts = rememberedInterrupts.length > 0 + ? rememberedInterrupts + : [{ id: response.interruptId, reason: 'approval' } satisfies Interrupt]; + const resume = buildResumeArray(interrupts, { + [response.interruptId]: response.status === 'resolved' + ? { status: 'resolved', payload: response.payload } + : { status: 'cancelled' }, + }); + if (!resume.some((entry) => entry.interruptId === response.interruptId)) { + throw new Error(`AG-UI interrupt ${response.interruptId} is not pending`); + } + this.activeRunId = runId; + return this.execute({ runId, resume }); + } + + abort(): void { + this.agent.abortRun(); + } + + private controllerFor(signal?: AbortSignal): AbortController | undefined { + if (!signal) return undefined; + const controller = new AbortController(); + if (signal.aborted) controller.abort(signal.reason); + signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true }); + return controller; + } + + private async execute(parameters: { + runId: string; + resume?: ReturnType; + abortController?: AbortController; + }): Promise { + let status: AguiRunStatus = 'completed'; + const subscriber: AgentSubscriber = { + onEvent: ({ event }) => { + const result = this.project(event, parameters.runId); + if (result.status) status = result.status; + result.events.forEach((item) => this.onEvent(item)); + }, + onRunFinishedEvent: ({ outcome }) => { + status = outcome === 'interrupt' ? 'interrupted' : 'completed'; + }, + onRunErrorEvent: () => { + status = 'failed'; + }, + }; + const result = await this.agent.runAgent({ + runId: parameters.runId, + context: [ksadkA2uiAgentContext], + forwardedProps: { injectA2UITool: true }, + resume: parameters.resume, + abortController: parameters.abortController, + }, subscriber); + const pending = this.agent.pendingInterrupts.slice(); + if (pending.length > 0) { + this.pendingByRun.set(parameters.runId, pending); + status = 'interrupted'; + } + return { status, result }; + } + + private project(event: BaseEvent, fallbackRunId: string): { events: RunEvent[]; status?: AguiRunStatus } { + const type = eventType(event); + const runId = eventRunId(event, fallbackRunId); + const messageId = eventMessageId(event, `${runId}:assistant`); + const payload = event as unknown as Record; + const events: RunEvent[] = []; + + if (type === 'RUN_STARTED') { + events.push({ type: 'activity', phase: 'AG-UI 运行已创建', status: 'running', countEvent: false }); + } else if (type === 'TEXT_MESSAGE_START') { + this.runMessageIds.set(runId, messageId); + events.push({ type: 'assistant_message_created', messageId }); + } else if (type === 'TEXT_MESSAGE_CONTENT') { + events.push({ type: 'text_delta', messageId: this.runMessageIds.get(runId) || messageId, delta: String(payload.delta || '') }); + } else if (type === 'TEXT_MESSAGE_END') { + events.push({ type: 'activity', phase: '生成回复内容', status: 'running' }); + } else if (type === 'REASONING_MESSAGE_CONTENT') { + events.push({ type: 'reasoning_delta', messageId: this.runMessageIds.get(runId) || messageId, delta: String(payload.delta || '') }); + } else if (type === 'TOOL_CALL_START') { + const toolCallId = String(payload.toolCallId || 'tool'); + this.tools.set(toolCallId, { name: String(payload.toolCallName || 'tool'), args: '' }); + events.push({ type: 'tool_upsert', messageId: this.runMessageIds.get(runId) || `${runId}:assistant`, name: String(payload.toolCallName || 'tool'), args: '', status: 'running' }); + } else if (type === 'TOOL_CALL_ARGS') { + const toolCallId = String(payload.toolCallId || 'tool'); + const tool = this.tools.get(toolCallId) || { name: 'tool', args: '' }; + tool.args += String(payload.delta || ''); + this.tools.set(toolCallId, tool); + events.push({ type: 'tool_upsert', messageId: this.runMessageIds.get(runId) || `${runId}:assistant`, name: tool.name, args: tool.args, status: 'running' }); + } else if (type === 'TOOL_CALL_RESULT') { + const toolCallId = String(payload.toolCallId || 'tool'); + const tool = this.tools.get(toolCallId) || { name: 'tool', args: '' }; + events.push({ type: 'tool_result', messageId: this.runMessageIds.get(runId) || `${runId}:assistant`, name: tool.name, output: String(payload.content || '') }); + } else if (type === 'ACTIVITY_SNAPSHOT') { + const content = payload.content; + const activity = asObject(content); + const surfaceId = String(activity.surfaceId || activity.surface_id || payload.messageId || 'default'); + events.push({ + type: 'agui_activity', + // A2UI operations belong to the assistant turn that produced them. + // Keeping the activity on a standalone message lets later text tokens + // push the card above the scroll position, which looks like it only + // appears after a history reload. + messageId: this.runMessageIds.get(runId) || messageId, + surfaceId, + messages: activityMessages(activity.content ?? content), + }); + } else if (type === 'RUN_FINISHED') { + const outcome = asObject(payload.outcome); + if (String(outcome.type || '').toLowerCase() === 'interrupt') { + const interrupts = Array.isArray(outcome.interrupts) ? outcome.interrupts : []; + this.pendingByRun.set(runId, interrupts as Interrupt[]); + for (const interrupt of interrupts as Interrupt[]) { + const metadata = asObject(interrupt.metadata); + const tool = interrupt.toolCallId ? this.tools.get(interrupt.toolCallId) : undefined; + const name = String( + metadata.tool_name + || metadata.toolName + || tool?.name + || interrupt.reason + || '人工确认', + ); + const args = stringifyPayload( + metadata.arguments + ?? metadata.tool_args + ?? metadata.args + ?? tool?.args, + ); + events.push({ + type: 'approval_requested', + messageId: this.runMessageIds.get(runId) || `${runId}:assistant`, + approvalRequestId: interrupt.id, + protocol: 'ag-ui', + name, + args, + ...(interrupt.message ? { message: interrupt.message } : {}), + ...(metadata.approval_level ? { approvalLevel: String(metadata.approval_level) } : {}), + }); + } + events.push({ type: 'activity', phase: '等待人工确认', status: 'waiting' }); + return { events, status: 'interrupted' }; + } + events.push({ type: 'terminal', status: 'completed' }); + } else if (type === 'RUN_ERROR') { + events.push({ type: 'error', error: new Error('AG-UI 运行失败') }); + return { events, status: 'failed' }; + } + return { events }; + } +} diff --git a/src/core/run/dispatcher.ts b/src/core/run/dispatcher.ts index 9ea0c92..55c9671 100644 --- a/src/core/run/dispatcher.ts +++ b/src/core/run/dispatcher.ts @@ -7,18 +7,17 @@ import { buildCompactionMessage } from '../../utils/session-events.js'; import { isFailedToolOutput } from '../../utils/tool-display.js'; import type { Message } from '../../components/chat/types.js'; -let assistantCreated = false; - const TERMINAL_COMPLETE_STATUSES = new Set(['completed']); const TERMINAL_ERROR_STATUSES = new Set(['failed', 'error', 'cancelled', 'canceled', 'aborted', 'incomplete']); function ensureAssistantMessage(id: string) { - if (assistantCreated) return; - assistantCreated = true; - useMessageStore.getState().patchMessages((prev) => [ - ...prev, - { id, role: 'model', content: '', timestamp: Date.now(), reasoning: '' }, - ]); + useMessageStore.getState().patchMessages((prev) => { + if (prev.some((message) => message.id === id)) return prev; + return [ + ...prev, + { id, role: 'model', content: '', timestamp: Date.now(), reasoning: '' }, + ]; + }); } function settleRunningToolsForTerminalStatus(status: string) { @@ -48,9 +47,6 @@ function settleRunningToolsForTerminalStatus(status: string) { export function dispatchRunEventToStores(event: RunEvent) { if (event.sessionId && useSessionStore.getState().currentSessionId !== event.sessionId) { - if (event.type === 'stage_changed' && (event.stage === 'completing' || event.stage === 'error' || event.stage === 'cancelled')) { - assistantCreated = false; - } return; } @@ -117,17 +113,24 @@ export function dispatchRunEventToStores(event: RunEvent) { ms.patchMessages((prev) => prev.map((msg) => { if (msg.id !== event.messageId) return msg; + const current = msg.tools?.[event.name]; + const currentApprovalResolved = current?.approvalStatus === 'approved' + || current?.approvalStatus === 'rejected'; return { ...msg, tools: { ...(msg.tools || {}), [event.name]: { - ...(msg.tools?.[event.name] || { name: event.name, args: '' }), + ...(current || { name: event.name, args: '' }), name: event.name, args: event.args, - status: event.status as NonNullable[string]['status'], + status: currentApprovalResolved + ? 'completed' + : event.status as NonNullable[string]['status'], ...(event.extra || {}), - ...(event.extra?.approvalRequestId ? { approvalStatus: 'pending' as const } : {}), + ...(event.extra?.approvalRequestId && !currentApprovalResolved + ? { approvalStatus: 'pending' as const } + : {}), }, }, }; @@ -156,6 +159,57 @@ export function dispatchRunEventToStores(event: RunEvent) { ); break; + case 'approval_requested': { + ensureAssistantMessage(event.messageId); + ms.patchMessages((prev) => + prev.map((msg) => { + if (msg.id !== event.messageId) return msg; + const existing = msg.tools?.[event.approvalRequestId]; + const alreadyResolved = existing?.approvalStatus === 'approved' + || existing?.approvalStatus === 'rejected'; + return { + ...msg, + tools: { + ...(msg.tools || {}), + [event.approvalRequestId]: { + ...(existing || {}), + name: event.name, + args: event.args, + status: alreadyResolved ? 'completed' : 'paused', + approvalRequestId: event.approvalRequestId, + approvalProtocol: event.protocol, + approvalStatus: alreadyResolved ? existing.approvalStatus : 'pending', + ...(event.message ? { approvalMessage: event.message } : {}), + ...(event.approvalLevel ? { approvalLevel: event.approvalLevel } : {}), + }, + }, + }; + }), + ); + break; + } + + case 'approval_resolved': + ms.patchMessages((prev) => + prev.map((msg) => { + if (!msg.tools) return msg; + let changed = false; + const tools = Object.fromEntries( + Object.entries(msg.tools).map(([key, tool]) => { + if (tool.approvalRequestId !== event.approvalRequestId) return [key, tool]; + changed = true; + return [key, { + ...tool, + status: 'completed' as const, + approvalStatus: event.decision, + }]; + }), + ) as NonNullable; + return changed ? { ...msg, tools } : msg; + }), + ); + break; + case 'system_message': ms.patchMessages((prev) => [ ...prev, @@ -194,7 +248,6 @@ export function dispatchRunEventToStores(event: RunEvent) { useStreamingStore.getState().setSessionStreaming(event.sessionId, true); } else if (event.stage === 'completing' || event.stage === 'error' || event.stage === 'cancelled') { useStreamingStore.getState().setSessionStreaming(event.sessionId, false); - assistantCreated = false; } break; @@ -207,7 +260,6 @@ export function dispatchRunEventToStores(event: RunEvent) { state.clearSessionActivity(event.sessionId); } }, 2400); - assistantCreated = false; break; case 'error': @@ -227,7 +279,6 @@ export function dispatchRunEventToStores(event: RunEvent) { timestamp: Date.now(), }, ]); - assistantCreated = false; break; case 'terminal': @@ -266,9 +317,111 @@ export function dispatchRunEventToStores(event: RunEvent) { } break; } + + case 'a2ui_surface_begin': { + const msgId = `a2ui-${event.surfaceId}`; + useMessageStore.getState().patchMessages((prev) => { + const without = prev.filter((m) => m.id !== msgId); + return [ + ...without, + { + id: msgId, + role: 'a2ui' as const, + content: '', + timestamp: Date.now(), + a2ui: { + surfaceId: event.surfaceId, + surface: event.surface, + }, + }, + ]; + }); + break; + } + + case 'a2ui_surface_update': { + const msgId = `a2ui-${event.surfaceId}`; + useMessageStore.getState().patchMessages((prev) => + prev.map((m) => + m.id === msgId && m.a2ui + ? { ...m, a2ui: { ...m.a2ui, surface: event.surface } } + : m, + ), + ); + break; + } + + case 'a2ui_surface_end': { + const msgId = `a2ui-${event.surfaceId}`; + useMessageStore.getState().patchMessages((prev) => + prev.map((m) => + m.id === msgId && m.a2ui + ? { ...m, a2ui: { ...m.a2ui, ended: true } } + : m, + ), + ); + break; + } + + case 'a2ui_interaction': { + const msgId = `a2ui-${event.surfaceId}`; + useMessageStore.getState().patchMessages((prev) => + prev.map((m) => + m.id === msgId && m.a2ui + ? { + ...m, + a2ui: { + ...m.a2ui, + pendingInteraction: { + interactionId: event.interactionId, + kind: event.kind, + inputSchema: event.inputSchema, + }, + }, + } + : m, + ), + ); + break; + } + + case 'agui_activity': { + const msgId = `agui-a2ui-${event.surfaceId}`; + useMessageStore.getState().patchMessages((prev) => { + const activity = { surfaceId: event.surfaceId, messages: event.messages }; + let attached = false; + const withAttachedActivity = prev.map((message) => { + if (message.id !== event.messageId) return message; + attached = true; + const prior = message.aguiActivities || []; + const next = [ + ...prior.filter((item) => item.surfaceId !== event.surfaceId), + activity, + ]; + return { ...message, aguiActivities: next }; + }); + if (attached) return withAttachedActivity; + + // An activity can legally arrive before the assistant message. Keep + // the existing standalone fallback for that edge case and for replay. + const current = prev.find((message) => message.id === msgId); + const nextMessage: Message = { + id: msgId, + role: 'a2ui', + content: '', + timestamp: current?.timestamp || Date.now(), + aguiActivity: activity, + }; + return current + ? prev.map((message) => message.id === msgId ? nextMessage : message) + : [...prev, nextMessage]; + }); + break; + } } } export function resetDispatcherState() { - assistantCreated = false; + // Kept for test and session lifecycle callers. Message existence is now the + // source of truth, so switching sessions cannot drop a live AG-UI event. } diff --git a/src/core/run/engine.ts b/src/core/run/engine.ts index d28f8e7..e5914ac 100644 --- a/src/core/run/engine.ts +++ b/src/core/run/engine.ts @@ -11,6 +11,7 @@ import { resolveRunAgentApiFormat } from '../../utils/layout-constants.js'; import { useStreamingStore } from '../../stores/streaming.js'; import type { StreamProtocol } from '../stream/types.js'; import type { RuntimeApiFormat } from '../../types/api.js'; +import { AguiRunClient } from './agui.js'; type StreamConsumeResult = { receivedData: boolean; @@ -94,6 +95,8 @@ export class RunEngineImpl implements RunEngine { private abortController: AbortController | null = null; private activeCompactionId: string | null = null; private activeSessionId: string | null = null; + private aguiClient: AguiRunClient | null = null; + private aguiThreadSessionId: string | null = null; private api: ApiFacade; private config: RunEngineConfig = { agentId: 'default-agent', @@ -125,6 +128,21 @@ export class RunEngineImpl implements RunEngine { } } + private getAguiClient(sessionId: string): AguiRunClient | null { + const transport = this.config.hostedChatTransport; + if (transport?.Protocol !== 'ag-ui' || !transport.Endpoint) return null; + if (!this.aguiClient || this.aguiThreadSessionId !== sessionId) { + this.aguiClient = new AguiRunClient({ + url: transport.Endpoint, + agentId: this.config.agentId, + threadId: sessionId, + onEvent: (event) => this.emit(event), + }); + this.aguiThreadSessionId = sessionId; + } + return this.aguiClient; + } + private setStage(stage: RunStage) { const allowed = VALID_TRANSITIONS[this._stage]; if (allowed && !allowed.includes(stage)) { @@ -182,6 +200,35 @@ export class RunEngineImpl implements RunEngine { const invocationId = createInvocationId(); useStreamingStore.getState().setCurrentRunId(invocationId); + const hostedTransport = this.config.hostedChatTransport; + const useAgui = !isResponsesResume + && draft.attachments.length === 0 + && hostedTransport?.Protocol === 'ag-ui'; + const aguiClient = useAgui ? this.getAguiClient(sessionId) : null; + if (aguiClient && hostedTransport) { + this.setStage('streaming'); + this.emit({ type: 'activity', phase: '等待 AG-UI 输出', status: 'waiting', countEvent: false }); + const aguiResult = await aguiClient.run( + draft.text, + invocationId, + this.abortController?.signal, + ); + if (aguiResult.status === 'interrupted') { + this.setStage('completing'); + this.emit({ type: 'stream_ended' }); + return; + } + if (aguiResult.status !== 'completed') { + this.setStage('error'); + this.emit({ type: 'activity', phase: 'AG-UI 运行失败', status: 'failed', countEvent: false }); + return; + } + this.setStage('completing'); + this.emit({ type: 'activity', phase: '运行完成', status: 'completed', countEvent: false }); + this.emit({ type: 'stream_ended' }); + return; + } + const body = this.buildRequestBody( sessionId, apiFormat, @@ -258,7 +305,7 @@ export class RunEngineImpl implements RunEngine { } } } finally { - useStreamingStore.getState().setStreaming(false); + useStreamingStore.getState().setSessionStreaming(sessionId, false); this.setStage('idle'); this.activeCompactionId = null; this.activeSessionId = null; @@ -278,6 +325,7 @@ export class RunEngineImpl implements RunEngine { }); } this.abortController?.abort(); + this.aguiClient?.abort(); useStreamingStore.getState().stopActivity( invocationId ? '已向运行时发送取消请求;如果当前框架只支持协作式取消,后台可能会在下一个安全点停止。' @@ -296,7 +344,8 @@ export class RunEngineImpl implements RunEngine { disconnect(): void { if (this._stage === 'idle') return; this.abortController?.abort(); - useStreamingStore.getState().setStreaming(false); + this.aguiClient?.abort(); + useStreamingStore.getState().setSessionStreaming(this.activeSessionId, false); useStreamingStore.getState().clearActivity(); this._stage = 'idle'; this.activeCompactionId = null; @@ -385,7 +434,7 @@ export class RunEngineImpl implements RunEngine { console.error('Failed to subscribe to run events:', error); } } finally { - useStreamingStore.getState().setStreaming(false); + useStreamingStore.getState().setSessionStreaming(params.sessionId, false); useStreamingStore.getState().setCurrentRunId(''); this.setStage('idle'); this.activeSessionId = null; @@ -503,7 +552,7 @@ export class RunEngineImpl implements RunEngine { this.emit({ type: 'error', error: error instanceof Error ? error : new Error(String(error)) }); } } finally { - useStreamingStore.getState().setStreaming(false); + useStreamingStore.getState().setSessionStreaming(params.sessionId, false); useStreamingStore.getState().setCurrentRunId(''); this.setStage('idle'); this.activeSessionId = null; @@ -514,6 +563,70 @@ export class RunEngineImpl implements RunEngine { return true; } + resumeAguiInterrupt(params: { + sessionId?: string | null; + interruptId: string; + status: 'resolved' | 'cancelled'; + payload?: unknown; + onSettled?: (sessionId: string | null) => void; + }): boolean { + if (this._stage !== 'idle') return false; + + const sessionId = params.sessionId || this.aguiThreadSessionId; + if (!sessionId) return false; + const aguiClient = this.getAguiClient(sessionId); + if (!aguiClient) return false; + this.activeSessionId = sessionId; + const invocationId = createInvocationId(); + useStreamingStore.getState().setCurrentRunId(invocationId); + this.setStage('connecting'); + this.emit({ type: 'activity', phase: '提交人工确认', status: 'connecting', countEvent: false }); + + void (async () => { + try { + this.setStage('streaming'); + const result = await aguiClient.resume(invocationId, { + interruptId: params.interruptId, + status: params.status, + payload: params.payload, + }); + const payload = params.payload && typeof params.payload === 'object' + ? params.payload as Record + : {}; + const rawDecision = String(payload.decision || payload.type || '').toLowerCase(); + this.emit({ + type: 'approval_resolved', + approvalRequestId: params.interruptId, + decision: params.status === 'cancelled' || rawDecision === 'reject' || rawDecision === 'rejected' + ? 'rejected' + : 'approved', + }); + if (result.status === 'interrupted') { + this.setStage('completing'); + this.emit({ type: 'stream_ended' }); + return; + } + if (result.status !== 'completed') { + this.setStage('error'); + this.emit({ type: 'activity', phase: '人工确认恢复失败', status: 'failed', countEvent: false }); + return; + } + this.setStage('completing'); + this.emit({ type: 'activity', phase: '运行完成', status: 'completed', countEvent: false }); + this.emit({ type: 'stream_ended' }); + } catch (error) { + this.setStage('error'); + this.emit({ type: 'error', error: error instanceof Error ? error : new Error(String(error)) }); + } finally { + useStreamingStore.getState().setCurrentRunId(''); + this.setStage('idle'); + this.activeSessionId = null; + params.onSettled?.(sessionId); + } + })(); + return true; + } + private async createSession(draft: { onSessionCreated?: (sessionId: string) => void; onSessionUpsert?: (sessionId: string) => void; @@ -724,7 +837,15 @@ export class RunEngineImpl implements RunEngine { this.emit({ type: 'tool_result', messageId, name: action.name, output: action.output }); break; case 'approval_request': - this.emit({ type: 'system_message', content: '本次运行需要人工审批后才能继续。' }); + this.emit({ + type: 'approval_requested', + messageId, + approvalRequestId: action.approvalRequestId, + protocol: 'responses', + name: '人工确认', + args: '', + message: '本次运行需要人工审批后才能继续。', + }); break; case 'incomplete': this.emit({ type: 'system_message', content: '本次运行已中断,需要人工确认后继续。' }); @@ -738,6 +859,18 @@ export class RunEngineImpl implements RunEngine { case 'compaction': this.emit({ type: 'compaction', phase: action.phase, trigger: action.trigger, compactedUntilSeqId: action.compactedUntilSeqId }); break; + case 'a2ui_surface_begin': + this.emit({ type: 'a2ui_surface_begin', surfaceId: action.surfaceId, surface: action.surface }); + break; + case 'a2ui_surface_update': + this.emit({ type: 'a2ui_surface_update', surfaceId: action.surfaceId, surface: action.surface }); + break; + case 'a2ui_surface_end': + this.emit({ type: 'a2ui_surface_end', surfaceId: action.surfaceId }); + break; + case 'a2ui_interaction': + this.emit({ type: 'a2ui_interaction', surfaceId: action.surfaceId, interactionId: action.interactionId, kind: action.kind, inputSchema: action.inputSchema }); + break; } } diff --git a/src/core/run/types.ts b/src/core/run/types.ts index 078bd58..f82001f 100644 --- a/src/core/run/types.ts +++ b/src/core/run/types.ts @@ -1,4 +1,5 @@ import type { RuntimeApiFormat } from '../../types/api.js'; +import type { HostedChatTransport } from '../../types/api.js'; import type { ModelCatalogItem } from '../../components/chat/types.js'; export type RunStage = @@ -25,12 +26,40 @@ export type RunEvent = | { type: 'reasoning_delta'; messageId: string; delta: string; sessionId?: string | null } | { type: 'tool_upsert'; messageId: string; name: string; args: string; status: string; extra?: Record; sessionId?: string | null } | { type: 'tool_result'; messageId: string; name: string; output: string; sessionId?: string | null } + | { + type: 'approval_requested'; + messageId: string; + approvalRequestId: string; + protocol: 'ag-ui' | 'responses'; + name: string; + args: string; + message?: string; + approvalLevel?: string; + sessionId?: string | null; + } + | { + type: 'approval_resolved'; + approvalRequestId: string; + decision: 'approved' | 'rejected'; + sessionId?: string | null; + } | { type: 'compaction'; phase: string; trigger?: string; compactedUntilSeqId?: number; sessionId?: string | null } | { type: 'system_message'; content: string; sessionId?: string | null } | { type: 'stream_ended'; sessionId?: string | null } | { type: 'error'; error: Error; sessionId?: string | null } | { type: 'terminal'; status: string; sessionId?: string | null } - | { type: 'stream_event'; event: import('../../types/session-events.js').SessionEventRecord; sessionId?: string | null }; + | { type: 'stream_event'; event: import('../../types/session-events.js').SessionEventRecord; sessionId?: string | null } + | { type: 'a2ui_surface_begin'; surfaceId: string; surface: import('../stream/types.js').A2UISurface; sessionId?: string | null } + | { type: 'a2ui_surface_update'; surfaceId: string; surface: import('../stream/types.js').A2UISurface; sessionId?: string | null } + | { type: 'a2ui_surface_end'; surfaceId: string; sessionId?: string | null } + | { type: 'a2ui_interaction'; surfaceId: string; interactionId: string; kind: string; inputSchema: Record; sessionId?: string | null } + | { + type: 'agui_activity'; + messageId: string; + surfaceId: string; + messages: Array>; + sessionId?: string | null; + }; export type RunEngineConfig = { agentId: string; @@ -39,6 +68,7 @@ export type RunEngineConfig = { selectedModel: string; selectedModelMetadata?: ModelCatalogItem | null; thinkingMode: string; + hostedChatTransport?: HostedChatTransport; checkpointResumePreviewEnabled?: boolean; }; @@ -70,6 +100,13 @@ export interface RunEngine { resumeAttemptId?: string; onSettled?: (sessionId: string | null) => void; }): boolean; + resumeAguiInterrupt(params: { + sessionId?: string | null; + interruptId: string; + status: 'resolved' | 'cancelled'; + payload?: unknown; + onSettled?: (sessionId: string | null) => void; + }): boolean; readonly stage: RunStage; subscribe(listener: (event: RunEvent) => void): () => void; } diff --git a/src/core/stream/responses-protocol.ts b/src/core/stream/responses-protocol.ts index 80b5548..e0719c2 100644 --- a/src/core/stream/responses-protocol.ts +++ b/src/core/stream/responses-protocol.ts @@ -32,6 +32,7 @@ export class ResponsesProtocol implements StreamProtocol { ...(approvalRequestId ? { approvalRequestId } : {}), ...(previousResponseId ? { previousResponseId } : {}), ...(serverLabel ? { serverLabel } : {}), + ...(approvalRequestId ? { approvalProtocol: 'responses' } : {}), }, } as StreamAction; } diff --git a/src/core/stream/types.ts b/src/core/stream/types.ts index 1d2299e..82b1614 100644 --- a/src/core/stream/types.ts +++ b/src/core/stream/types.ts @@ -1,3 +1,17 @@ +export interface A2UIComponent { + component_id: string; + type: string; + props: Record; + children: A2UIComponent[]; +} + +export interface A2UISurface { + surface_id: string; + catalog_id: string; + components: A2UIComponent[]; + data_model: Record; +} + export type StreamAction = | { type: 'text_delta'; text: string } | { type: 'text_final'; text: string } @@ -5,6 +19,10 @@ export type StreamAction = | { type: 'tool_upsert'; name: string; args: string; status: 'running' | 'completed' | 'error' | 'paused'; extra?: Record } | { type: 'tool_result'; name: string; output: string } | { type: 'approval_request'; approvalRequestId: string; previousResponseId?: string } + | { type: 'a2ui_surface_begin'; surfaceId: string; surface: A2UISurface } + | { type: 'a2ui_surface_update'; surfaceId: string; surface: A2UISurface } + | { type: 'a2ui_surface_end'; surfaceId: string } + | { type: 'a2ui_interaction'; surfaceId: string; interactionId: string; kind: string; inputSchema: Record } | { type: 'compaction'; phase: 'start' | 'done' | 'failed'; trigger?: string; compactedUntilSeqId?: number } | { type: 'incomplete' } | { type: 'failed'; message: string } diff --git a/src/hooks/useRunAgent.ts b/src/hooks/useRunAgent.ts index 02323c7..ced6db5 100644 --- a/src/hooks/useRunAgent.ts +++ b/src/hooks/useRunAgent.ts @@ -9,6 +9,8 @@ import type { ApiFacade } from '../core/api/types.js'; import { RunEngineImpl, dispatchRunEventToStores, resetDispatcherState } from '../core/run/index.js'; import type { ModelCatalogItem, Session } from '../components/chat/types.js'; import { writePersistedSessionId } from '../utils/session.js'; +import { resolveHostedChatTransport } from '../utils/capabilities.js'; +import type { A2UIClientEventMessage } from '@copilotkit/a2ui-renderer'; type QueuedDraft = { text: string; @@ -57,9 +59,10 @@ export function useRunAgent(ctx: RunAgentContext) { selectedModel, selectedModelMetadata, thinkingMode, + hostedChatTransport: resolveHostedChatTransport(uiCapabilities), checkpointResumePreviewEnabled: Boolean(uiCapabilities.RunLifecycle?.CheckpointResumePreview), }); - }, [agentId, apiFormats, agentFramework, selectedModel, selectedModelMetadata, thinkingMode, uiCapabilities.RunLifecycle?.CheckpointResumePreview]); + }, [agentId, apiFormats, agentFramework, selectedModel, selectedModelMetadata, thinkingMode, uiCapabilities]); const getEngine = useCallback((sessionId: string | null | undefined) => { const key = String(sessionId || 'new-session'); @@ -235,5 +238,63 @@ export function useRunAgent(ctx: RunAgentContext) { resetDispatcherState(); }, []); - return { submitDraft, stopGeneration, disconnectRun, resumeCheckpoint, resetCompaction }; + const submitAguiAction = useCallback((message: A2UIClientEventMessage) => { + const action = message.userAction; + if (!action) return false; + const context = action.context || {}; + const interruptId = String(context.interruptId || context.interrupt_id || ''); + if (!interruptId) return false; + const sessionId = currentSessionIdRef.current; + if (!sessionId) return false; + const engine = getEngine(sessionId); + const status = context.status === 'cancelled' ? 'cancelled' : 'resolved'; + const payload = Object.prototype.hasOwnProperty.call(context, 'payload') + ? context.payload + : { + action: action.name, + sourceComponentId: action.sourceComponentId, + context, + }; + return engine.resumeAguiInterrupt({ + sessionId, + interruptId, + status, + payload, + onSettled: onRunSettled, + }); + }, [currentSessionIdRef, getEngine, onRunSettled]); + + const respondToAguiApproval = useCallback((options: { + interruptId: string; + approve: boolean; + }) => { + if (!options.interruptId) return false; + const sessionId = currentSessionIdRef.current; + if (!sessionId) return false; + const engine = getEngine(sessionId); + if (engine.stage !== 'idle') return false; + + useStreamingStore.getState().setSessionStreaming(sessionId, true); + const accepted = engine.resumeAguiInterrupt({ + sessionId, + interruptId: options.interruptId, + status: 'resolved', + payload: { decision: options.approve ? 'approve' : 'reject' }, + onSettled: onRunSettled, + }); + if (!accepted) { + useStreamingStore.getState().setSessionStreaming(sessionId, false); + } + return accepted; + }, [currentSessionIdRef, getEngine, onRunSettled]); + + return { + submitDraft, + stopGeneration, + disconnectRun, + resumeCheckpoint, + submitAguiAction, + respondToAguiApproval, + resetCompaction, + }; } diff --git a/src/hooks/useSessionLifecycle.ts b/src/hooks/useSessionLifecycle.ts index b1bac02..bd34d19 100644 --- a/src/hooks/useSessionLifecycle.ts +++ b/src/hooks/useSessionLifecycle.ts @@ -284,6 +284,7 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { && loadSessionGenerationRef.current === generation ); useSessionStore.getState().setCurrentSessionId(sessionId); + useSessionStore.getState().setSessionInitialMessageHistoryLoading(sessionId, true); resetCompaction(); runSubscriptionAbortRef.current?.abort(); if (isMobile) { @@ -366,6 +367,10 @@ export function useSessionLifecycle(ctx: SessionLifecycleContext) { } } catch (error) { console.error('Failed to load session messages:', error); + } finally { + if (isStillCurrentSession()) { + useSessionStore.getState().setSessionInitialMessageHistoryLoading(sessionId, false); + } } }, [ diff --git a/src/index.css b/src/index.css index 26d0197..aeb3820 100644 --- a/src/index.css +++ b/src/index.css @@ -1,6 +1,31 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; +@plugin "@tailwindcss/typography"; +@plugin "tailwindcss-animate"; + +@theme { + --color-primary: hsl(215 78% 52%); + --color-primary-foreground: hsl(0 0% 100%); + --color-accent: hsl(215 78% 95%); + --color-accent-foreground: hsl(215 78% 25%); + --color-background: hsl(210 20% 99%); + --color-foreground: hsl(215 25% 15%); + --color-muted: hsl(210 15% 96%); + --color-muted-foreground: hsl(215.4 16.3% 46.9%); + --color-border: hsl(210 12% 90%); + --color-card: hsl(0 0% 100%); + --color-card-foreground: hsl(222.2 84% 4.9%); + --color-popover: hsl(0 0% 100%); + --color-popover-foreground: hsl(222.2 84% 4.9%); + --color-secondary: hsl(210 40% 96.1%); + --color-secondary-foreground: hsl(222.2 47.4% 11.2%); + --color-destructive: hsl(0 84.2% 60.2%); + --color-destructive-foreground: hsl(210 40% 98%); + --color-input: hsl(214.3 31.8% 91.4%); + --color-ring: hsl(222.2 84% 4.9%); + --radius: 0.75rem; +} + +@custom-variant dark (&:where(.dark, .dark *)); @layer base { :root { diff --git a/src/stores/session.ts b/src/stores/session.ts index b1b0086..8616233 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -16,6 +16,7 @@ export type SessionState = { messageHistory: Record; }; @@ -39,6 +40,7 @@ export type SessionActions = { hasMore: boolean; isLoadingOlder?: boolean; }) => void; + setSessionInitialMessageHistoryLoading: (sessionId: string, loading: boolean) => void; setSessionMessageHistoryLoading: (sessionId: string, loading: boolean) => void; clearSessionMessageHistory: (sessionId?: string) => void; }; @@ -111,7 +113,10 @@ export const useSessionStore = create()((set) => ({ sessionsPageSize: 30, loadedPages: new Set(), hasMoreSessions: false, - isLoadingSessions: false, + // Session restoration starts from an unknown state. Rendering an empty + // transcript before the first list request completes makes persisted + // approvals look as if they only appear after a manual refresh. + isLoadingSessions: true, pinnedSessionIds: readPinnedSessionIds(), messageHistory: {}, setSessions: (sessions) => @@ -195,10 +200,26 @@ export const useSessionStore = create()((set) => ({ [sessionId]: { nextCursor: history.nextCursor, hasMore: history.hasMore, + isLoadingInitial: false, isLoadingOlder: history.isLoadingOlder ?? false, }, }, })), + setSessionInitialMessageHistoryLoading: (sessionId, loading) => + set((s) => { + const existing = s.messageHistory[sessionId]; + return { + messageHistory: { + ...s.messageHistory, + [sessionId]: { + nextCursor: existing?.nextCursor ?? null, + hasMore: existing?.hasMore ?? false, + isLoadingInitial: loading, + isLoadingOlder: existing?.isLoadingOlder ?? false, + }, + }, + }; + }), setSessionMessageHistoryLoading: (sessionId, loading) => set((s) => { const existing = s.messageHistory[sessionId]; diff --git a/src/stores/streaming.ts b/src/stores/streaming.ts index 7b1db57..5bcbe65 100644 --- a/src/stores/streaming.ts +++ b/src/stores/streaming.ts @@ -19,6 +19,7 @@ export type StreamingState = { stopRequested: boolean; activity: RunActivity | null; sessionActivities: Record; + sessionStreaming: Record; }; export type StreamingActions = { @@ -52,9 +53,13 @@ export type StreamingActions = { export type StreamingStore = StreamingState & StreamingActions; -const isActivityActive = (activity: RunActivity | null | undefined): boolean => ( - Boolean(activity && activity.status !== 'completed' && activity.status !== 'failed' && activity.status !== 'stopped') -); +const hasStreamingSession = (sessions: Record): boolean => Object.keys(sessions).length > 0; + +const withoutStreamingSession = (sessions: Record, key: string): Record => { + const next = { ...sessions }; + delete next[key]; + return next; +}; export const useStreamingStore = create()((set, get) => ({ isStreaming: false, @@ -62,26 +67,21 @@ export const useStreamingStore = create()((set, get) => ({ stopRequested: false, activity: null, sessionActivities: {}, + sessionStreaming: {}, setStreaming: (streaming) => set({ isStreaming: streaming }), setSessionStreaming: (sessionId, streaming) => set((state) => { const key = String(sessionId || ''); if (!key) return { isStreaming: streaming }; - if (!streaming) { - const current = state.sessionActivities[key]; - if (!current) { - return { isStreaming: Object.values(state.sessionActivities).some(isActivityActive) }; - } - return { - isStreaming: Object.entries(state.sessionActivities).some(([id, activity]) => ( - id !== key && isActivityActive(activity) - )), - }; - } - return { isStreaming: true }; + const remaining = withoutStreamingSession(state.sessionStreaming, key); + const sessionStreaming = streaming ? { ...remaining, [key]: true as const } : remaining; + return { + sessionStreaming, + isStreaming: hasStreamingSession(sessionStreaming), + }; }), isSessionStreaming: (sessionId) => { - const activity = get().getSessionActivity(sessionId); - return isActivityActive(activity); + const key = String(sessionId || ''); + return Boolean(key && get().sessionStreaming[key]); }, getSessionActivity: (sessionId) => { const key = String(sessionId || ''); @@ -127,11 +127,7 @@ export const useStreamingStore = create()((set, get) => ({ }; if (key) { return { - isStreaming: nextActivity.status !== 'completed' && nextActivity.status !== 'failed' && nextActivity.status !== 'stopped' - ? true - : Object.entries(state.sessionActivities).some(([id, existing]) => ( - id !== key && existing.status !== 'completed' && existing.status !== 'failed' && existing.status !== 'stopped' - )), + isStreaming: hasStreamingSession(state.sessionStreaming), sessionActivities: { ...state.sessionActivities, [key]: nextActivity, @@ -174,12 +170,12 @@ export const useStreamingStore = create()((set, get) => ({ lastEventAt: Date.now(), }; const sessionActivities = { ...state.sessionActivities, [key]: nextActivity }; + const sessionStreaming = withoutStreamingSession(state.sessionStreaming, key); return { - isStreaming: Object.entries(sessionActivities).some(([id, activity]) => ( - id !== key && activity.status !== 'completed' && activity.status !== 'failed' && activity.status !== 'stopped' - )), + isStreaming: hasStreamingSession(sessionStreaming), activity: nextActivity, sessionActivities, + sessionStreaming, }; }), clearActivity: () => set({ activity: null }), @@ -187,11 +183,20 @@ export const useStreamingStore = create()((set, get) => ({ const key = String(sessionId || ''); if (!key) return {}; const { [key]: _removed, ...sessionActivities } = state.sessionActivities; + const sessionStreaming = withoutStreamingSession(state.sessionStreaming, key); return { sessionActivities, - isStreaming: Object.values(sessionActivities).some((activity) => activity.status !== 'completed' && activity.status !== 'failed' && activity.status !== 'stopped'), + sessionStreaming, + isStreaming: hasStreamingSession(sessionStreaming), activity: state.activity === _removed ? null : state.activity, }; }), - resetRun: () => set({ isStreaming: false, currentRunId: '', stopRequested: false, activity: null, sessionActivities: {} }), + resetRun: () => set({ + isStreaming: false, + currentRunId: '', + stopRequested: false, + activity: null, + sessionActivities: {}, + sessionStreaming: {}, + }), })); diff --git a/src/types/api.ts b/src/types/api.ts index 43ba189..1e57ac3 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -1 +1,15 @@ -export type RuntimeApiFormat = 'responses' | 'chat_completions'; \ No newline at end of file +export type RuntimeApiFormat = 'responses' | 'chat_completions'; + +export type HostedChatTransportProtocol = 'ag-ui' | 'responses'; + +export type HostedChatTransport = { + Protocol: HostedChatTransportProtocol; + Runtime: string; + Endpoint: string; + Version: string; + Capabilities: { + A2UI: boolean; + Interrupt: boolean; + Cancel: boolean; + }; +}; diff --git a/src/types/capabilities.ts b/src/types/capabilities.ts index 5eca6db..1c78fb6 100644 --- a/src/types/capabilities.ts +++ b/src/types/capabilities.ts @@ -1,4 +1,8 @@ -import type { RuntimeApiFormat } from './api.js'; +import type { + HostedChatTransport, + HostedChatTransportProtocol, + RuntimeApiFormat, +} from './api.js'; export type BuiltinToolCapability = { name: string; @@ -23,6 +27,8 @@ export type UiCapabilities = { HostedChat: { Enabled: boolean; ApiFormats: RuntimeApiFormat[]; + PreferredTransport: HostedChatTransportProtocol; + Transports: HostedChatTransport[]; }; NativeDashboard: { Enabled: boolean; diff --git a/src/utils/capabilities.js b/src/utils/capabilities.js index c0856e6..85755eb 100644 --- a/src/utils/capabilities.js +++ b/src/utils/capabilities.js @@ -60,6 +60,32 @@ function normalizeBuiltinTools(value) { }); } +function normalizeHostedChatTransports(value) { + if (!Array.isArray(value)) { + return []; + } + return value.flatMap((item) => { + const transport = asObject(item); + const protocol = String(transport.Protocol || '').trim().toLowerCase(); + const endpoint = String(transport.Endpoint || '').trim(); + if (!['ag-ui', 'responses'].includes(protocol) || !endpoint.startsWith('/')) { + return []; + } + const capabilities = asObject(transport.Capabilities); + return [{ + Protocol: protocol, + Runtime: String(transport.Runtime || '').trim(), + Endpoint: endpoint, + Version: String(transport.Version || '').trim(), + Capabilities: { + A2UI: Boolean(capabilities.A2UI), + Interrupt: Boolean(capabilities.Interrupt), + Cancel: Boolean(capabilities.Cancel), + }, + }]; + }); +} + export function normalizeCapabilities(bootstrap) { const data = bootstrap?.Data || bootstrap || {}; const rawCapabilities = asObject(data.Capabilities); @@ -79,6 +105,16 @@ export function normalizeCapabilities(bootstrap) { const nativeDashboard = asObject(rawCapabilities.NativeDashboard); const nativeTerminal = asObject(rawCapabilities.NativeTerminal); const runLifecycle = asObject(rawCapabilities.RunLifecycle); + const topLevelHostedChat = asObject(data.HostedChat); + const transports = normalizeHostedChatTransports( + hostedChat.Transports || topLevelHostedChat.Transports, + ); + const preferredCandidate = String( + hostedChat.PreferredTransport || topLevelHostedChat.PreferredTransport || 'responses', + ).trim().toLowerCase(); + const preferredTransport = transports.some( + (transport) => transport.Protocol === preferredCandidate, + ) ? preferredCandidate : 'responses'; const hostedChatEnabled = normalizeEnabled(hostedChat.Enabled, defaultHostedChat); const nativeDashboardEnabled = normalizeEnabled( @@ -93,6 +129,8 @@ export function normalizeCapabilities(bootstrap) { HostedChat: { Enabled: hostedChatEnabled, ApiFormats: normalizeApiFormats(hostedChat.ApiFormats || apiFormats), + PreferredTransport: preferredTransport, + Transports: transports, }, NativeDashboard: { Enabled: nativeDashboardEnabled, @@ -149,3 +187,20 @@ export function isNativeDashboardEnabled(capabilities) { export function isNativeTerminalEnabled(capabilities) { return normalizeCapabilities({ Data: { Capabilities: capabilities } }).NativeTerminal.Enabled; } + +export function resolveHostedChatTransport(capabilities) { + const hostedChat = normalizeCapabilities({ Data: { Capabilities: capabilities } }).HostedChat; + const preferred = hostedChat.Transports.find( + (transport) => transport.Protocol === hostedChat.PreferredTransport, + ); + const responses = hostedChat.Transports.find( + (transport) => transport.Protocol === 'responses', + ); + return preferred || responses || { + Protocol: 'responses', + Runtime: 'ksadk', + Endpoint: '/v1/responses', + Version: 'v1', + Capabilities: { A2UI: false, Interrupt: false, Cancel: false }, + }; +} diff --git a/src/utils/messages.js b/src/utils/messages.js index d8743bb..71ae815 100644 --- a/src/utils/messages.js +++ b/src/utils/messages.js @@ -58,6 +58,11 @@ function mapToolEvents(toolEvents) { if (te.ApprovalRequestId) { entry.approvalRequestId = te.ApprovalRequestId; entry.approvalStatus = APPROVAL_STATUS_MAP[String(te.Status ?? 'paused').toLowerCase()] ?? 'pending'; + entry.approvalProtocol = String(te.Protocol ?? '').toLowerCase() === 'ag-ui' + ? 'ag-ui' + : 'responses'; + if (te.ApprovalMessage) entry.approvalMessage = String(te.ApprovalMessage); + if (te.ApprovalLevel) entry.approvalLevel = String(te.ApprovalLevel); } if (te.ToolCallId) { entry.previousResponseId = te.ToolCallId; @@ -104,6 +109,29 @@ export function mapBackendMessage(msg) { return result; } +function mapBackendActivities(msg) { + if (!Array.isArray(msg.Activities)) return []; + return msg.Activities.flatMap((activity, index) => { + const surfaceId = String(activity?.SurfaceId || ''); + if (!surfaceId) return []; + const content = activity?.Content; + const messages = Array.isArray(content?.a2ui_operations) + ? content.a2ui_operations + : Array.isArray(content) + ? content + : []; + if (!messages.length) return []; + return [{ + id: activity.MessageId || `a2ui-${msg.MessageId || msg.SeqId || 'message'}-${index}`, + role: 'a2ui', + content: '', + timestamp: parseTimestamp(msg.Timestamp), + aguiActivity: { surfaceId, messages: normalizeA2uiOperations(messages) }, + }]; + }); +} + export function mapBackendMessages(messages) { - return messages.map(mapBackendMessage); + return messages.flatMap((message) => [mapBackendMessage(message), ...mapBackendActivities(message)]); } +import { normalizeA2uiOperations } from '../core/run/a2ui.js'; diff --git a/src/utils/responses-stream.js b/src/utils/responses-stream.js index 56e1a37..42a3e20 100644 --- a/src/utils/responses-stream.js +++ b/src/utils/responses-stream.js @@ -115,6 +115,28 @@ function completedOutputItems(data) { return Array.isArray(payload?.output) ? payload.output : []; } +function unwrapInterruptInfo(value) { + let current = value; + if (typeof current === 'string') { + try { + current = JSON.parse(current); + } catch { + return {}; + } + } + if (Array.isArray(current)) { + current = current[0] || {}; + } + if (!current || typeof current !== 'object') return {}; + if (current.value && typeof current.value === 'object' && !Array.isArray(current.value)) { + return { + ...current.value, + approval_request_id: current.value.approval_request_id || current.value.id || current.id, + }; + } + return current; +} + function normalizeOutputItem({ data, state, status }) { const item = data?.item || data?.output_item || data || {}; const type = String(item.type || '').trim(); @@ -276,16 +298,89 @@ export function normalizeResponsesStreamEvent({ eventName, data, state }) { } if (eventType === 'response.approval_request' || eventType === 'response.ksadk.approval_request') { - const interruptInfo = data?.interrupt_info && typeof data.interrupt_info === 'object' ? data.interrupt_info : {}; + const interruptInfo = unwrapInterruptInfo(data?.interrupt_info); + const approvalRequestId = String(interruptInfo.approval_request_id || interruptInfo.id || ''); + const previousResponseId = String(data?.response_id || state.currentResponseId || ''); + // 把审批详情(工具名/参数/允许决定)转成可交互 tool_upsert(status=paused), + // 让 ChatMessageList 渲染 ApprovalBar(批准/拒绝按钮),而不是只出一句系统消息。 + // 兼容两种嵌套:interrupt_info.approval_requests.action_requests(外层包装) + // 与 interrupt_info.action_requests(runner 直出)。 + const ar = (interruptInfo.approval_requests && typeof interruptInfo.approval_requests === 'object') + ? interruptInfo.approval_requests + : interruptInfo; + const actionRequests = Array.isArray(ar.action_requests) ? ar.action_requests : []; + if (actionRequests.length > 0) { + return actionRequests.map((req) => ({ + type: 'tool_upsert', + name: String(req?.name || 'tool'), + args: JSON.stringify(req?.args ?? {}), + status: 'paused', + approvalRequestId, + previousResponseId, + })); + } return [ { type: 'approval_request', - approvalRequestId: String(interruptInfo.approval_request_id || interruptInfo.id || ''), - previousResponseId: String(data?.response_id || state.currentResponseId || ''), + approvalRequestId, + previousResponseId, }, ]; } + // A2UI surface 生命周期。兼容两种命名: + // - ksadk 冻结命名(G0.2):a2ui.surface.begin / .update / .end + // - a2ui.org v1.0 官方协议:createSurface / updateComponents / deleteSurface + // 前端统一归一成内部 StreamAction,后续若后端切官方协议,前端零改。 + const surfaceBeginTypes = new Set([ + 'response.ksadk.a2ui_surface_begin', 'a2ui.surface.begin', + 'response.a2ui.createSurface', 'a2ui.createSurface', 'createSurface', + ]); + if (surfaceBeginTypes.has(eventType)) { + const surface = data?.surface && typeof data.surface === 'object' ? data.surface : {}; + return [{ + type: 'a2ui_surface_begin', + surfaceId: String(data?.surface_id || data?.surfaceId || surface.surface_id || surface.surfaceId || ''), + surface, + }]; + } + + const surfaceUpdateTypes = new Set([ + 'response.ksadk.a2ui_surface_update', 'a2ui.surface.update', + 'response.a2ui.updateComponents', 'a2ui.updateComponents', 'updateComponents', + ]); + if (surfaceUpdateTypes.has(eventType)) { + const surface = data?.surface && typeof data.surface === 'object' ? data.surface : {}; + return [{ + type: 'a2ui_surface_update', + surfaceId: String(data?.surface_id || data?.surfaceId || surface.surface_id || surface.surfaceId || ''), + surface, + }]; + } + + const surfaceEndTypes = new Set([ + 'response.ksadk.a2ui_surface_end', 'a2ui.surface.end', + 'response.a2ui.deleteSurface', 'a2ui.deleteSurface', 'deleteSurface', + ]); + if (surfaceEndTypes.has(eventType)) { + return [{ type: 'a2ui_surface_end', surfaceId: String(data?.surface_id || data?.surfaceId || '') }]; + } + + // A2UI 交互(input_required)。官方 v1.0 经 actionResponse 承载同步回包; + // 此处归一 interaction(input_required 登记),兼容 ksadk 冻结命名 a2ui.interaction。 + const interactionTypes = new Set([ + 'response.ksadk.a2ui_interaction', 'a2ui.interaction', + ]); + if (interactionTypes.has(eventType)) { + return [{ + type: 'a2ui_interaction', + surfaceId: String(data?.surface_id || data?.surfaceId || ''), + interactionId: String(data?.interaction_id || data?.interactionId || ''), + kind: String(data?.kind || 'input'), + inputSchema: data?.input_schema && typeof data.input_schema === 'object' ? data.input_schema : {}, + }]; + } + const fallbackText = data?.content?.parts?.[0]?.text; if (fallbackText && !data?.actions?.finishReason) { return [{ type: 'text_delta', text: String(fallbackText) }]; diff --git a/tests/message-virtualization.test.mjs b/tests/message-virtualization.test.mjs index f265332..b515012 100644 --- a/tests/message-virtualization.test.mjs +++ b/tests/message-virtualization.test.mjs @@ -53,3 +53,27 @@ test('message virtualization honors measured heights when available', async () = assert.ok(windowed.totalHeight > items.length * 100); assert.ok(windowed.visibleItems.some((entry) => entry.item.id === 'msg-2')); }); + +test('message virtualization moves later rows after an expanded row is remeasured', async () => { + const virtualization = await loadMessageVirtualizationUtils(); + const items = [{ id: 'reasoning' }, { id: 'approval' }, { id: 'result' }]; + + const collapsed = virtualization.calculateVirtualMessageWindow({ + items, + viewportHeight: 1000, + overscan: 0, + defaultItemHeight: 100, + }); + const expanded = virtualization.calculateVirtualMessageWindow({ + items, + viewportHeight: 1000, + overscan: 0, + defaultItemHeight: 100, + measuredHeights: new Map([['reasoning', 320]]), + }); + + assert.equal(collapsed.visibleItems[1].top, 100); + assert.equal(expanded.visibleItems[1].top, 320); + assert.equal(expanded.visibleItems[2].top, 420); + assert.equal(expanded.totalHeight, 520); +}); diff --git a/tests/responses-stream.test.mjs b/tests/responses-stream.test.mjs index e5c7237..4fe4810 100644 --- a/tests/responses-stream.test.mjs +++ b/tests/responses-stream.test.mjs @@ -118,6 +118,36 @@ test('responses stream utils expose standard mcp approval request resume metadat ); }); +test('responses stream utils project wrapped LangGraph HITL interrupts immediately', async () => { + const responsesStream = await loadResponsesStreamUtils(); + assert.ok(responsesStream, 'expected Responses stream helpers to exist'); + const state = responsesStream.createResponsesStreamState(); + + assert.deepEqual( + responsesStream.normalizeResponsesStreamEvent({ + eventName: 'response.approval_request', + data: { + interrupt_info: [{ + id: 'interrupt-1', + value: { + action_requests: [{ name: 'write_file', args: { path: '/tmp/x.txt' } }], + review_configs: [{ allowed_decisions: ['approve', 'reject'] }], + }, + }], + }, + state, + }), + [{ + type: 'tool_upsert', + name: 'write_file', + args: '{"path":"/tmp/x.txt"}', + status: 'paused', + approvalRequestId: 'interrupt-1', + previousResponseId: '', + }], + ); +}); + test('responses stream utils normalize reasoning summary and completed text variants', async () => { const responsesStream = await loadResponsesStreamUtils(); diff --git a/vite.config.ts b/vite.config.ts index b564d46..46a9d64 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -30,4 +30,4 @@ export default defineConfig({ } } } -}) \ No newline at end of file +}) From 54f9d2223589ace800e9097c25672238cb554f1f Mon Sep 17 00:00:00 2001 From: xiayu Date: Fri, 24 Jul 2026 16:30:42 +0800 Subject: [PATCH 03/61] test(web): cover AG-UI approval and A2UI replay --- .gitignore | 3 + docs/a2ui-frontend-integration-plan.md | 115 +++++++++++++ e2e/agui.spec.mjs | 215 +++++++++++++++++++++++++ playwright.agui.config.mjs | 17 ++ 4 files changed, 350 insertions(+) create mode 100644 docs/a2ui-frontend-integration-plan.md create mode 100644 e2e/agui.spec.mjs create mode 100644 playwright.agui.config.mjs diff --git a/.gitignore b/.gitignore index fb0e775..38f67ff 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ dist-hosted/ dist-ksadk/ dist-lib/ coverage/ +output/ +test-results/ +.playwright-cli/ *.tsbuildinfo *.tgz *.tgz.sha256 diff --git a/docs/a2ui-frontend-integration-plan.md b/docs/a2ui-frontend-integration-plan.md new file mode 100644 index 0000000..90560a1 --- /dev/null +++ b/docs/a2ui-frontend-integration-plan.md @@ -0,0 +1,115 @@ +# A2UI And AG-UI Integration + +## Status + +KSADK Web uses the official transports and renderer: + +- `@ag-ui/client` owns streaming, interrupts, resume payloads, and aborts. +- `@copilotkit/a2ui-renderer` owns catalog validation, A2UI state, rendering, + and user actions. +- KSADK's `RuntimeAdapter` and `RuntimeEvent` remain the backend's common + execution and persistence model. Neither library is replaced by a custom + browser SSE protocol. + +The old proposal for a private `SubmitA2UIAction` endpoint and a hand-written +`A2UISurface` component is retired. New work must not revive either path. + +## Transport Boundary + +`GetAgentUiBootstrap` advertises the usable transports. The web client selects +AG-UI only when it is explicitly advertised as valid: + +```json +{ + "HostedChat": { + "PreferredTransport": "ag-ui", + "Transports": [ + { + "Protocol": "ag-ui", + "Runtime": "copilotkit", + "Endpoint": "/agentengine/agui", + "Version": "0.1.19", + "Capabilities": { "A2UI": true, "Interrupt": true, "Cancel": true } + }, + { + "Protocol": "responses", + "Runtime": "ksadk", + "Endpoint": "/v1/responses", + "Version": "v1", + "Capabilities": { "A2UI": false, "Interrupt": true, "Cancel": true } + } + ] + } +} +``` + +`/v1/responses` preserves the OpenAI Responses contract. It is not relabelled +as AG-UI and it does not gain a second, incompatible A2UI protocol. If AG-UI +is absent or malformed, the client falls back to Responses. + +## Live Run And Resume + +`src/core/run/agui.ts` creates an official `HttpAgent` with the server's +advertised endpoint. Every run carries the official A2UI catalog context and +`injectA2UITool: true`. `AguiRunClient` projects AG-UI events to the existing +run dispatcher: + +| AG-UI event | Web projection | +| --- | --- | +| `TEXT_MESSAGE_*` | assistant message and deltas | +| `REASONING_MESSAGE_CONTENT` | reasoning delta | +| `TOOL_CALL_*` | tool activity/result | +| `ACTIVITY_SNAPSHOT` | A2UI activity attached to the producing assistant turn | +| interrupted `RUN_FINISHED` | pending approval card | + +Approval accepts or rejects through `RunEngine.resumeAguiInterrupt`. The +client builds the official AG-UI resume array through `buildResumeArray`; it +does not invent a KSADK-only action endpoint. A durable interrupt can be +resumed after a page reload because the session and interrupt id are sent back +to the runtime, which remains authoritative. + +The existing Responses approval path remains independent and continues to use +the OpenAI-compatible approval resume input. Do not merge the two payload +formats in the browser. + +## A2UI Rendering + +`src/components/chat/A2UIActivityMessage.tsx` renders activity messages with +`A2UIProvider`, `A2UIRenderer`, and the official v0.9 `basicCatalog`. The only +compatibility repair is `normalizeA2uiOperations`: it renames one persisted +legacy `*-root` component id to `root`, which is the identifier expected by the +official renderer. Valid current A2UI messages are never rewritten. + +Renderer callbacks pass `A2UIClientEventMessage` directly to the AG-UI run +hook. This supports more than approval: any catalog-supported form, selection, +or action can carry its own `userAction.context` and resume the matching +interrupt. Policy enforcement, actor validation, idempotency, and tool receipt +checks remain backend responsibilities. + +## Replay And UI Rules + +- A2UI activities are persisted as RuntimeEvents and replayed into the same + assistant turn as live events. +- A pending approval is rendered immediately when its `RUN_FINISHED` interrupt + arrives; it must not depend on a history refresh. +- A resolved approval stays terminal after replay. A duplicated pending event + must not make a completed decision actionable again. +- The renderer is a message-row surface, not a floating overlay. On a narrow + viewport it remains in normal document flow above the composer. + +## Verification + +Required automated checks: + +```bash +npm run lint +npm test +node --test tests/*.mjs +npm run build:all +``` + +Backend protocol coverage lives in `ksadk-python/tests/agui/` and validates +AG-UI wire format, RuntimeAdapter ownership, LangGraph interrupts, A2UI +projection, and application factory wiring. A browser smoke must additionally +verify an advertised AG-UI endpoint, live activity rendering, approval resume, +history replay, and desktop/mobile layout before release. diff --git a/e2e/agui.spec.mjs b/e2e/agui.spec.mjs new file mode 100644 index 0000000..fd30c3c --- /dev/null +++ b/e2e/agui.spec.mjs @@ -0,0 +1,215 @@ +import { expect, test } from '@playwright/test'; + +const SESSION_ID = 'session-agui-e2e'; +const CATALOG_ID = 'https://a2ui.org/specification/v0_9/basic_catalog.json'; + +function envelope(data) { + return { Code: 0, Message: 'Success', Data: data }; +} + +function statusOperations() { + return [ + { + version: 'v0.9', + createSurface: { surfaceId: 'fixture-status', catalogId: CATALOG_ID }, + }, + { + version: 'v0.9', + updateComponents: { + surfaceId: 'fixture-status', + components: [ + { id: 'root', component: 'Column', children: ['fixture-status-title'] }, + { + id: 'fixture-status-title', + component: 'Text', + variant: 'h3', + text: 'E2E 状态卡', + }, + ], + }, + }, + ]; +} + +function sse(events) { + return events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join(''); +} + +function bootstrap() { + return { + Agent: { AgentId: 'fixture-agent', Name: 'AG-UI Fixture', Framework: 'langgraph' }, + ApiFormats: ['responses'], + Capabilities: { + Attachments: false, + WorkspaceFiles: false, + Approval: true, + Thinking: true, + StopRun: true, + ResumeRun: true, + }, + HostedChat: { + PreferredTransport: 'ag-ui', + Transports: [ + { + Protocol: 'ag-ui', + Runtime: 'copilotkit', + Endpoint: '/agentengine/agui', + Version: '0.1.19', + Capabilities: { A2UI: true, Interrupt: true, Cancel: true }, + }, + { + Protocol: 'responses', + Runtime: 'ksadk', + Endpoint: '/v1/responses', + Version: 'v1', + Capabilities: { A2UI: false, Interrupt: true, Cancel: true }, + }, + ], + }, + Model: { id: 'fixture-model', display_name: 'Fixture Model' }, + }; +} + +async function installFixture(page) { + const state = { approved: false, created: false, aguiBodies: [] }; + + await page.route('**/agentengine/agui', async (route) => { + const body = route.request().postDataJSON(); + state.aguiBodies.push(body); + const isResume = Array.isArray(body.resume) && body.resume.length > 0; + const events = isResume + ? [ + { type: 'RUN_STARTED', threadId: SESSION_ID, runId: body.runId }, + { type: 'TEXT_MESSAGE_START', messageId: 'assistant-resumed', role: 'assistant' }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: 'assistant-resumed', delta: '审批已完成。' }, + { type: 'TEXT_MESSAGE_END', messageId: 'assistant-resumed' }, + { type: 'RUN_FINISHED', threadId: SESSION_ID, runId: body.runId, outcome: { type: 'success' } }, + ] + : [ + { type: 'RUN_STARTED', threadId: SESSION_ID, runId: body.runId }, + { type: 'TEXT_MESSAGE_START', messageId: 'assistant-approval', role: 'assistant' }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: 'assistant-approval', delta: '需要人工确认。' }, + { type: 'TOOL_CALL_START', toolCallId: 'tool-write', toolCallName: 'write_file' }, + { type: 'TOOL_CALL_ARGS', toolCallId: 'tool-write', delta: '{"path":"demo.txt"}' }, + { + type: 'ACTIVITY_SNAPSHOT', + messageId: 'activity-status', + activityType: 'a2ui-surface', + content: { surfaceId: 'fixture-status', a2ui_operations: statusOperations() }, + }, + { type: 'TEXT_MESSAGE_END', messageId: 'assistant-approval' }, + { type: 'TOOL_CALL_END', toolCallId: 'tool-write' }, + { + type: 'RUN_FINISHED', + threadId: SESSION_ID, + runId: body.runId, + outcome: { + type: 'interrupt', + interrupts: [{ + id: 'approval-write', + reason: 'approval', + message: '确认写入 demo.txt?', + toolCallId: 'tool-write', + metadata: { + tool_name: 'write_file', + arguments: { path: 'demo.txt' }, + approval_level: 'elevated', + }, + }], + }, + }, + ]; + await route.fulfill({ + status: 200, + contentType: 'text/event-stream', + body: sse(events), + }); + }); + + await page.route('**/agentengine/api/v1/**', async (route) => { + const action = new URL(route.request().url()).pathname.split('/').pop(); + if (action === 'CreateSession') state.created = true; + const history = state.approved + ? [ + { + MessageId: 'assistant-approval', + Role: 'assistant', + Content: { text: '需要人工确认。' }, + ToolEvents: [{ + Name: 'write_file', + Args: { path: 'demo.txt' }, + Status: 'approved', + ApprovalRequestId: 'approval-write', + Protocol: 'ag-ui', + }], + Activities: [{ + SurfaceId: 'fixture-status', + Content: { a2ui_operations: statusOperations() }, + }], + }, + { + MessageId: 'assistant-resumed', + Role: 'assistant', + Content: { text: '审批已完成。' }, + }, + ] + : []; + const payloadByAction = { + GetAgentUiBootstrap: bootstrap(), + ListSessions: { + Sessions: state.created + ? [{ SessionId: SESSION_ID, AgentId: 'fixture-agent', Title: 'AG-UI fixture' }] + : [], + Total: state.created ? 1 : 0, + Page: 1, + PageSize: 30, + }, + ListAgentModels: { Models: [{ id: 'fixture-model', display_name: 'Fixture Model' }] }, + CreateSession: { Session: { SessionId: SESSION_ID, AgentId: 'fixture-agent' } }, + GetSession: { Session: { SessionId: SESSION_ID, AgentId: 'fixture-agent' } }, + ListSessionMessages: { Messages: history, LatestSeqId: history.length, HasMore: false, NextCursor: null }, + ListSessionCheckpoints: { Checkpoints: [] }, + ListToolReceipts: { ToolReceipts: [] }, + GetResponseFeedback: null, + }; + await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(envelope(payloadByAction[action] ?? {})) }); + }); + return state; +} + +test('projects AG-UI activity, resumes approval, and replays terminal state', async ({ page }) => { + const fixture = await installFixture(page); + await page.goto('/'); + + await expect(page.getByText('AG-UI Fixture')).toBeVisible(); + const composer = page.getByPlaceholder('发送消息...'); + await composer.fill('请写入 demo.txt'); + await composer.press('Enter'); + + await expect(page.getByText('E2E 状态卡')).toBeVisible(); + await expect(page.locator('summary').filter({ hasText: '等待审批' })).toBeVisible(); + await expect(page.getByRole('button', { name: '批准并继续' })).toBeVisible(); + await page.getByRole('button', { name: '批准并继续' }).click(); + + await expect.poll(() => fixture.aguiBodies.length).toBe(2); + expect(fixture.aguiBodies[1].resume).toEqual([ + { + interruptId: 'approval-write', + status: 'resolved', + payload: { decision: 'approve' }, + }, + ]); + await expect(page.getByText('审批已完成。')).toBeVisible(); + await expect(page.locator('summary').filter({ hasText: '已批准' })).toBeVisible(); + + fixture.approved = true; + await page.reload(); + await expect(page.getByText('E2E 状态卡')).toBeVisible(); + await expect(page.getByText('审批已完成。')).toBeVisible(); + await expect(page.getByRole('button', { name: '批准并继续' })).toHaveCount(0); + + await page.setViewportSize({ width: 390, height: 844 }); + await expect(composer).toBeInViewport(); + await expect(page.getByText('E2E 状态卡')).toBeInViewport(); + expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true); +}); diff --git a/playwright.agui.config.mjs b/playwright.agui.config.mjs new file mode 100644 index 0000000..f732b17 --- /dev/null +++ b/playwright.agui.config.mjs @@ -0,0 +1,17 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './e2e', + testMatch: 'agui.spec.mjs', + timeout: 30_000, + use: { + baseURL: 'http://127.0.0.1:4173', + viewport: { width: 1280, height: 900 }, + screenshot: 'only-on-failure', + }, + webServer: { + command: 'npm run dev -- --host 127.0.0.1 --port 4173 --strictPort', + url: 'http://127.0.0.1:4173', + reuseExistingServer: false, + }, +}); From 098f66e559de2bc49d2e0055fa6107c4aab61885 Mon Sep 17 00:00:00 2001 From: xiayu Date: Fri, 24 Jul 2026 16:50:45 +0800 Subject: [PATCH 04/61] fix(deps): update transitive dompurify security patch --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b892ef..244577c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7321,9 +7321,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz", - "integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" From 36ce6b0b375cbc61a2b83f1bbd6ebdec837e2635 Mon Sep 17 00:00:00 2001 From: xiayu Date: Fri, 24 Jul 2026 17:28:46 +0800 Subject: [PATCH 05/61] chore(release): prepare ksadk-web 0.3.0 review candidate --- CHANGELOG.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7b84d7..a4dcab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ # Changelog +## 0.3.0 - 2026-07-24 + +> **Review candidate, not a published npm release.** `0.3.0` is the web +> counterpart of the KsADK `0.8.0` review branch. No npm tag or package is +> created by this changelog entry. + +### Hosted runtime transport + +- Add the official `@ag-ui/client` transport and capability-driven runtime + dispatcher for Hosted Chat. The existing OpenAI Responses stream remains the + default compatibility path whenever AG-UI is unavailable or not negotiated. +- Make the transport choice a run concern instead of a second page or client: + session restoration, composer state, streaming state, and the API facade + stay shared across Responses and AG-UI. + +### A2UI and approvals + +- Render RuntimeEvent-projected A2UI activities through + `@copilotkit/a2ui-renderer`, with a bounded activity surface that works in + the message timeline and on compact viewports. +- Persist and replay activity/approval state with session history. A pending + card can appear after a reload without a manual refresh; an answered card is + terminal and does not submit the same approval again. +- Route approval answers through the existing resume contract and expose + explicit pending, responding, resolved, and error UI states. UI actions do + not replace backend approval or tool policy enforcement. + +### Session and UI fixes + +- Repair restored-session history projection, event cursor merging, and active + approval hydration so a switch/reload does not erase messages or leave a + stale interactive card above the current run. +- Refine expandable activity layout and mobile spacing so A2UI content remains + within the chat flow instead of overlaying neighboring messages. + +### Tooling and compatibility + +- Migrate the app styling pipeline to Tailwind CSS v4. +- Update the locked DOMPurify transitive dependency security patch. +- This candidate requires the corresponding Hosted runtime capability. It does + not make a new npm package available to `ksadk-python`; Python remains pinned + to the currently published web package until a reviewed npm publication + occurs. + ## 0.2.18 - 2026-07-08 - Load restored sessions through the server-projected `ListSessionMessages` diff --git a/package-lock.json b/package-lock.json index 244577c..e2f556d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@kingsoftcloud/ksadk-web", - "version": "0.2.19", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@kingsoftcloud/ksadk-web", - "version": "0.2.19", + "version": "0.3.0", "license": "Apache-2.0", "dependencies": { "@ag-ui/client": "0.0.57", diff --git a/package.json b/package.json index 2f1aa22..03c3ebd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kingsoftcloud/ksadk-web", - "version": "0.2.19", + "version": "0.3.0", "type": "module", "scripts": { "dev": "vite", From 993c7c5891f12cb62520bf44bbaa34f2b325bb6b Mon Sep 17 00:00:00 2001 From: xiayu Date: Fri, 24 Jul 2026 23:57:27 +0800 Subject: [PATCH 06/61] feat(markdown): preserve line breaks in chat message rendering Add remark-breaks so single newlines in assistant output render as hard breaks instead of collapsing to a space, fixing lost line breaks in streamed/plain-text agent replies. Applied to both the plain and math-enabled markdown renderers. Co-Authored-By: Claude Opus 4.8 (1M context) --- package-lock.json | 30 +++++++++++++++++++ package.json | 1 + src/components/MessageMarkdown.tsx | 3 +- .../markdown/MathMessageMarkdown.tsx | 3 +- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e2f556d..c65c74c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "react-markdown": "^10.1.0", "react-syntax-highlighter": "^16.1.1", "rehype-katex": "^7.0.1", + "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", "remark-math": "^6.0.0", "tailwind-merge": "^3.5.0", @@ -9322,6 +9323,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-newline-to-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz", + "integrity": "sha512-MbgeFca0hLYIEx/2zGsszCSEJJ1JSCdiY5xQxRcLDDGa8EPvlLPupJ4DSajbMPAnC0je8jfb9TiUATnxxrHUog==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-find-and-replace": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-phrasing": { "version": "4.1.0", "resolved": "https://registry.npmmirror.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", @@ -10825,6 +10840,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-breaks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz", + "integrity": "sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-newline-to-break": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-cjk-friendly": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/remark-cjk-friendly/-/remark-cjk-friendly-1.2.3.tgz", diff --git a/package.json b/package.json index 03c3ebd..e4f4b3c 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "react-markdown": "^10.1.0", "react-syntax-highlighter": "^16.1.1", "rehype-katex": "^7.0.1", + "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", "remark-math": "^6.0.0", "tailwind-merge": "^3.5.0", diff --git a/src/components/MessageMarkdown.tsx b/src/components/MessageMarkdown.tsx index 1bc616e..fe7d66c 100644 --- a/src/components/MessageMarkdown.tsx +++ b/src/components/MessageMarkdown.tsx @@ -1,6 +1,7 @@ import React, { Suspense } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; +import remarkBreaks from 'remark-breaks'; import { preprocessMarkdown } from '../utils/markdown.js'; const LazyCodeBlock = React.lazy(() => @@ -87,7 +88,7 @@ const PlainMarkdown: React.FC<{ content: string }> = React.memo(({ content }) => return (
{processedContent} diff --git a/src/components/markdown/MathMessageMarkdown.tsx b/src/components/markdown/MathMessageMarkdown.tsx index ca48902..7789b18 100644 --- a/src/components/markdown/MathMessageMarkdown.tsx +++ b/src/components/markdown/MathMessageMarkdown.tsx @@ -2,6 +2,7 @@ import React from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; +import remarkBreaks from 'remark-breaks'; import rehypeKatex from 'rehype-katex'; import 'katex/dist/katex.min.css'; import { CodeBlock } from './CodeBlock.js'; @@ -67,7 +68,7 @@ export const MathMessageMarkdown: React.FC = React.mem return (
From 598f09cfbd472634fbc7c06485d1f634f83d6ce8 Mon Sep 17 00:00:00 2001 From: xiayu Date: Tue, 28 Jul 2026 08:42:32 +0800 Subject: [PATCH 07/61] feat(web): align chat UI with wework style + streaming reconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 整体风格向 wework 看齐,覆盖配色/字体/侧边栏/输入框/消息区/工具渲染/错误展示: - 设计 token: primary 改 teal、surface/text-*/sidebar 独立灰阶对齐 wework 精确值, 字体栈加 PingFang SC/Microsoft YaHei, 基础圆角 0.5rem - 侧边栏: 会话行 h-[30px] rounded-[10px] + sidebar 灰阶, 右侧操作按钮 hover 才显示, 时间 label hover 时让位避免与删除按钮重叠 - 输入框: 双层 26px 圆角(外层 surface 软阴影/内层 background 细边), 底部工具栏左组(附件+model+思考 chip)右组(上下文环+发送钮), model/思考改 wework 自定义下拉 MenuChip(替代原生 select), 附件 badge 改色块+文件名/大小+悬浮圆形删除钮 - 上下文长度: wework 圆环指示器(conic-gradient 进度环,>=85% 转 red,hover 弹 tooltip) - 消息区: user 气泡 bg-muted 右对齐, assistant 居中窄栏平铺, hover 浮出操作行(复制+反馈快捷,opacity 切换) - 工具/审批卡: 审批按钮 rounded-full bg-foreground + ghost 拒绝, 去掉 emerald 绿 - 错误/限流: StatusBanner 内联状态条(限流 amber+倒计时/网络 spinner/失败重试), engine 识别 429 emit rate_limited 事件, 不再白屏 - 流式重连: 记录 lastSeqId, 网络断线改用 resumeRun(afterSeqId) 续订而非从头重跑 - 回到底部圆钮 + 流式思考占位 Co-Authored-By: Claude Fable 5 --- src/components/chat/ChatComposer.tsx | 230 +++++++++------ src/components/chat/ChatHeader.tsx | 8 +- src/components/chat/ChatMessageList.tsx | 61 +++- src/components/chat/ChatSidebar.tsx | 86 +++--- src/components/chat/ContextUsageIndicator.tsx | 41 +++ src/components/chat/MenuChip.tsx | 75 +++++ src/components/chat/ProcessingBlocksView.tsx | 276 ++++++++++++++++++ src/components/chat/StatusBanner.tsx | 81 +++++ src/components/chat/types.ts | 5 + src/core/run/blocks.ts | 140 +++++++++ src/core/run/dispatcher.ts | 70 ++++- src/core/run/engine.ts | 27 ++ src/core/run/types.ts | 1 + src/index.css | 72 +++-- src/stores/streaming.ts | 25 ++ tailwind.config.ts | 33 ++- 16 files changed, 1052 insertions(+), 179 deletions(-) create mode 100644 src/components/chat/ContextUsageIndicator.tsx create mode 100644 src/components/chat/MenuChip.tsx create mode 100644 src/components/chat/ProcessingBlocksView.tsx create mode 100644 src/components/chat/StatusBanner.tsx create mode 100644 src/core/run/blocks.ts diff --git a/src/components/chat/ChatComposer.tsx b/src/components/chat/ChatComposer.tsx index c961e56..77761ec 100644 --- a/src/components/chat/ChatComposer.tsx +++ b/src/components/chat/ChatComposer.tsx @@ -7,10 +7,15 @@ import type { RefObject, } from 'react'; -import { Paperclip, Send, ShieldCheck, StopCircle } from 'lucide-react'; +import { ArrowUp, Paperclip, Square } from 'lucide-react'; import { cn } from '@/lib/utils'; +import { useModelStore } from '@/stores/model.js'; +import type { ModelStore } from '@/stores/model.js'; +import { normalizeThinkingMode } from '@/utils/model-options.js'; +import { ContextUsageIndicator } from './ContextUsageIndicator'; +import { MenuChip } from './MenuChip'; import type { ComposerContextIndicator } from './types'; type ChatComposerProps = { @@ -53,6 +58,22 @@ export function ChatComposer({ const placeholderText = isMobile ? '发送消息...' : '发送消息... (Shift + Enter 换行)'; const activeStopTitle = onCancelRemote ? '保留恢复点并结束本次执行' : '停止生成'; + // wework 风格:model/思考 chip 放输入框工具栏(从 model store 直读,不经 props)。 + const availableModels = useModelStore((s: ModelStore) => s.availableModels); + const selectedModel = useModelStore((s: ModelStore) => s.selectedModel); + const thinkingMode = useModelStore((s: ModelStore) => s.thinkingMode); + const setSelectedModel = useModelStore((s: ModelStore) => s.setSelectedModel); + const setThinkingMode = useModelStore((s: ModelStore) => s.setThinkingMode); + const selectedModelLabel = + availableModels.find((m) => m.id === selectedModel)?.display_name || selectedModel || ''; + const thinkingLabel = (mode: 'auto' | 'enabled' | 'disabled') => + mode === 'enabled' ? '开启思考' : mode === 'disabled' ? '关闭思考' : '思考自动'; + const formatFileSize = (bytes: number) => { + if (bytes < 1024) return `${bytes} B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; + return `${(bytes / 1024 / 1024).toFixed(1)} MB`; + }; + const handleDrop = (event: DragEvent) => { event.preventDefault(); event.stopPropagation(); @@ -85,7 +106,7 @@ export function ChatComposer({ }; return ( -
+
{queuedDrafts.length > 0 ? (
@@ -99,12 +120,12 @@ export function ChatComposer({ return (
{index + 1} - + {preview} {draft.attachments.length > 0 ? ( @@ -124,61 +145,47 @@ export function ChatComposer({
) : null} -
-
{ - event.preventDefault(); - event.stopPropagation(); - }} - onDrop={handleDrop} - className="relative flex min-w-0 flex-1 flex-col rounded-[1.25rem] border border-slate-200 bg-white p-1.5 shadow-[0_8px_22px_rgba(15,23,42,0.07)] transition-all focus-within:border-slate-300 focus-within:ring-1 focus-within:ring-slate-300 dark:border-slate-700 dark:bg-slate-900 dark:focus-within:border-slate-600 dark:focus-within:ring-slate-600" - > - {attachments.length > 0 ? ( -
- {attachments.map((file, index) => ( -
- - {file.name} - - -
- ))} -
- ) : null} - -
- + + + + + {file.name} + {formatFileSize(file.size)} + + +
+ ))} +
+ ) : null}