From ddeebf6ead8857c8e15e2d4f58dbc3ef9557eb3e Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Thu, 27 Aug 2026 12:35:46 +0300 Subject: [PATCH 1/2] TopScout init --- package.json | 14 +- .../ChallengeList/ChallengeList.module.scss | 1 + .../ChallengeList/ChallengeList.tsx | 89 +- .../src/config/routes.config.ts | 2 + .../src/customer-portal.routes.tsx | 2 + .../components/NavTabs/config/tabs-config.ts | 4 + .../AssistantCard/AssistantCard.module.scss | 82 + .../AssistantCard/AssistantCard.tsx | 32 + .../pages/assistants/AssistantCard/index.ts | 1 + .../AssistantsPage/AssistantsPage.module.scss | 37 + .../AssistantsPage/AssistantsPage.tsx | 28 + .../pages/assistants/AssistantsPage/index.ts | 1 + .../TopScoutPage/TopScoutPage.module.scss | 81 + .../assistants/TopScoutPage/TopScoutPage.tsx | 123 ++ .../ChatThread/ChatThread.module.scss | 273 ++++ .../components/ChatThread/ChatThread.tsx | 238 +++ .../ChatThread/MarkdownText.module.scss | 132 ++ .../components/ChatThread/MarkdownText.tsx | 32 + .../components/ChatThread/index.ts | 1 + .../ThreadSidebar/ThreadSidebar.module.scss | 108 ++ .../ThreadSidebar/ThreadSidebar.tsx | 125 ++ .../components/ThreadSidebar/index.ts | 1 + .../pages/assistants/TopScoutPage/index.ts | 1 + .../assistants/TopScoutPage/lib/auth-fetch.ts | 18 + .../TopScoutPage/lib/chat.service.ts | 39 + .../assistants/TopScoutPage/lib/constants.ts | 28 + .../TopScoutPage/lib/convert-messages.ts | 111 ++ .../assistants/TopScoutPage/lib/index.ts | 5 + .../assistants/TopScoutPage/lib/models.ts | 26 + .../pages/assistants/assistants.routes.tsx | 41 + .../assistants/config/assistants-config.ts | 22 + src/config/environments/default.env.ts | 5 + .../environments/global-config.model.ts | 1 + src/libs/shared/lib/services/ai-workflows.tsx | 70 +- tsconfig.json | 2 +- yarn.lock | 1371 ++++++++++++++++- 36 files changed, 3107 insertions(+), 40 deletions(-) create mode 100644 src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.module.scss create mode 100644 src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.tsx create mode 100644 src/apps/customer-portal/src/pages/assistants/AssistantCard/index.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.module.scss create mode 100644 src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.tsx create mode 100644 src/apps/customer-portal/src/pages/assistants/AssistantsPage/index.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.module.scss create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.tsx create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.module.scss create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.tsx create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.module.scss create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.tsx create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/index.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.module.scss create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.tsx create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/index.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/index.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/auth-fetch.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/chat.service.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/constants.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/convert-messages.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/index.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/models.ts create mode 100644 src/apps/customer-portal/src/pages/assistants/assistants.routes.tsx create mode 100644 src/apps/customer-portal/src/pages/assistants/config/assistants-config.ts diff --git a/package.json b/package.json index 667c8db70..b07177bff 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,10 @@ "deploy:dev": "BRANCH=$(git rev-parse --abbrev-ref HEAD) && TAG=\"dev-${BRANCH}\" && git tag -d \"$TAG\" 2>/dev/null; git push origin \":refs/tags/$TAG\" 2>/dev/null; git tag \"$TAG\" && git push origin \"$TAG\"" }, "dependencies": { + "@ai-sdk/react": "4.0.82", + "@assistant-ui/react": "0.15.16", + "@assistant-ui/react-ai-sdk": "1.4.7", + "@assistant-ui/react-markdown": "0.14.12", "@codemirror/autocomplete": "^6.20.1", "@codemirror/lang-java": "^6.0.2", "@codemirror/language": "^6.12.2", @@ -42,6 +46,7 @@ "@tinymce/tinymce-react": "^6.3.0", "@types/codemirror": "5.60.17", "@uiw/react-codemirror": "^4.25.8", + "ai": "7.0.79", "amazon-s3-uri": "^0.1.1", "apexcharts": "^3.54.1", "axios": "^1.19.0", @@ -64,10 +69,12 @@ "express-interceptor": "^1.2.0", "fflate": "^0.8.2", "filestack-js": "^3.44.2", + "flag-icons": "^6.7.0", "highcharts": "^10.3.3", "highcharts-react-official": "^3.2.3", "highlight.js": "^11.11.1", "html2canvas": "^1.4.1", + "i18n-iso-countries": "^3.7.1", "lodash": "^4.18.1", "markdown-it": "^14.3.0", "marked": "4.3.0", @@ -115,6 +122,7 @@ "remark-breaks": "^3.0.3", "remark-frontmatter": "^4.0.1", "remark-gfm": "^3.0.1", + "remark-gfm-v4": "npm:remark-gfm@^4.0.1", "remark-parse": "^11.0.0", "remove": "^0.1.5", "sanitize-html": "^2.17.6", @@ -123,12 +131,10 @@ "swr": "^1.3.0", "tc-auth-lib": "topcoder-platform/tc-auth-lib#v2.0", "tinymce": "^7.9.1", - "typescript": "^4.9.5", + "typescript": "5.5.4", "universal-navigation": "https://github.com/topcoder-platform/universal-navigation#master", "uuid": "^11.1.0", - "yup": "^1.7.1", - "flag-icons": "^6.7.0", - "i18n-iso-countries": "^3.7.1" + "yup": "^1.7.1" }, "devDependencies": { "@babel/core": "^7.29.6", diff --git a/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.module.scss b/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.module.scss index 34cf58249..611d07661 100644 --- a/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.module.scss +++ b/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.module.scss @@ -54,6 +54,7 @@ } } + .desktopTable { td { vertical-align: middle; diff --git a/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx b/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx index c53fac7ca..bdb6b9f87 100644 --- a/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx +++ b/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx @@ -1,12 +1,20 @@ -import { Dispatch, FC, SetStateAction, useContext, useMemo, useState } from 'react' +import { + Dispatch, + FC, + SetStateAction, + useContext, + useMemo, + useState, +} from 'react' import { Link, useNavigate } from 'react-router-dom' +import { toast } from 'react-toastify' import _ from 'lodash' import cn from 'classnames' import moment from 'moment' import { ChevronDownIcon } from '@heroicons/react/solid' import { EnvironmentConfig } from '~/config' -import { useWindowSize, WindowSize } from '~/libs/shared' +import { ingestChallengeInRag, useWindowSize, WindowSize } from '~/libs/shared' import { Button, Table, type TableColumn } from '~/libs/ui' import { ReactComponent as RegistrantUserIcon } from '../../assets/i/registrant-user-icon.svg' @@ -22,12 +30,10 @@ import { useEventCallback } from '../../hooks' import { Challenge, ChallengeFilterCriteria, ChallengeType } from '../../models' import { Paging } from '../../models/challenge-management/Pagination' import { checkIsMM } from '../../utils/challenge' +import { handleError } from '../../utils' import { MobileListView } from './MobileListView' -import { - canOpenReviewUi, - getReviewUiChallengeUrl, -} from './reviewUiLink' +import { canOpenReviewUi, getReviewUiChallengeUrl } from './reviewUiLink' import { getChallengeSubTrackSuffix } from './challengeTypeTrack' import styles from './ChallengeList.module.scss' @@ -68,19 +74,25 @@ const ChallengeCurrentPhase: FC<{ challenge: Challenge }> = props => { const ChallengeUserStats: FC<{ challenge: Challenge }> = props => (
1 ? 's' : ''}`} + title={`${props.challenge.numOfRegistrants} registrant${ + props.challenge.numOfRegistrants > 1 ? 's' : '' + }`} > {props.challenge.numOfRegistrants} 1 ? 's' : ''}`} + title={`${props.challenge.numOfSubmissions} submission${ + props.challenge.numOfSubmissions > 1 ? 's' : '' + }`} > {props.challenge.numOfSubmissions} 1 ? 's' : ''}`} + title={`${props.challenge.groups.length} group${ + props.challenge.groups.length > 1 ? 's' : '' + }`} > {props.challenge.groups.length} @@ -131,10 +143,7 @@ const TrackIcon: FC<{ challenge: Challenge }> = props => { const trackName = props.challenge.track?.name || '' return ( -
+
{type?.abbreviation}
) @@ -145,6 +154,7 @@ const Actions: FC<{ currentFilters: ChallengeFilterCriteria }> = props => { const [openDropdown, setOpenDropdown] = useState(false) + const [isIngesting, setIsIngesting] = useState(false) const navigate = useNavigate() const isMM = useMemo(() => checkIsMM(props.challenge), [props.challenge]) const goToManageUser = useEventCallback(() => { @@ -153,6 +163,38 @@ const Actions: FC<{ }) }) + const handleIngestInRag = useEventCallback(async () => { + if (isIngesting) { + return + } + + setIsIngesting(true) + const toastId = toast.loading( + `Ingesting "${props.challenge.name}" into RAG…`, + ) + + try { + const report = await ingestChallengeInRag(props.challenge.id) + + const message = report.skipped + ? 'Challenge has no description to index — nothing to ingest.' + : `Challenge ingested into RAG successfully (${report.chunks} ` + + `chunk${report.chunks === 1 ? '' : 's'}).` + + toast.update(toastId, { + autoClose: 5000, + isLoading: false, + render: message, + type: 'success', + }) + } catch (error) { + toast.dismiss(toastId) + handleError(error) + } finally { + setIsIngesting(false) + } + }) + const manageDropdownMenuTrigger = useEventCallback( (triggerProps: { open: boolean @@ -223,13 +265,24 @@ const Actions: FC<{ {isMM && (
  • Marathon Match
  • )} +
  • + Upsert for TopScout +
  • @@ -240,7 +293,9 @@ const Actions: FC<{ classNames={{ menu: 'challenge-list-actions-dropdown-menu' }} >
      -
    • +
    • {hasChallengeDetailsAccess && ( )} - {!hasChallengeDetailsAccess && Challenge Details} + {!hasChallengeDetailsAccess && ( + Challenge Details + )}
    • {hasWorkManagerAccess && ( diff --git a/src/apps/customer-portal/src/config/routes.config.ts b/src/apps/customer-portal/src/config/routes.config.ts index 0e5a652a0..cd8c1fa64 100644 --- a/src/apps/customer-portal/src/config/routes.config.ts +++ b/src/apps/customer-portal/src/config/routes.config.ts @@ -13,3 +13,5 @@ export const showcaseSearchRouteId = 'showcase' export const flexiTalentRouteId = 'flexi-talent' export const statisticsRouteId = 'statistics' export const skillStatisticsRouteId = 'skill-statistics' +export const assistantsRouteId = 'assistants' +export const topScoutRouteId = 'topScout' diff --git a/src/apps/customer-portal/src/customer-portal.routes.tsx b/src/apps/customer-portal/src/customer-portal.routes.tsx index d0033c8be..18cb1f7ce 100644 --- a/src/apps/customer-portal/src/customer-portal.routes.tsx +++ b/src/apps/customer-portal/src/customer-portal.routes.tsx @@ -19,6 +19,7 @@ import { customerPortalTalentSearchRoutes } from './pages/talent-search/talent-s import { customerPortalProjectShowcaseRoutes } from './pages/project-showcase/project-showcase.routes' import { customerPortalSkillStatisticsRoutes } from './pages/skill-statistics/skill-statistics.routes' import { customerPortalStatisticsRoutes } from './pages/statistics/statistics.routes' +import { customerPortalAssistantsRoutes } from './pages/assistants/assistants.routes' const CustomerPortalApp: LazyLoadedComponent = lazyLoad(() => import('./CustomerPortalApp')) @@ -39,6 +40,7 @@ export const customerPortalRoutes: ReadonlyArray = [ ...customerPortalTalentSearchRoutes, ...customerPortalProjectShowcaseRoutes, ...customerPortalFlexiTalentRoutes, + ...customerPortalAssistantsRoutes, ], domain: AppSubdomain.customer, element: , diff --git a/src/apps/customer-portal/src/lib/components/NavTabs/config/tabs-config.ts b/src/apps/customer-portal/src/lib/components/NavTabs/config/tabs-config.ts index 75c25f041..fad60b55d 100644 --- a/src/apps/customer-portal/src/lib/components/NavTabs/config/tabs-config.ts +++ b/src/apps/customer-portal/src/lib/components/NavTabs/config/tabs-config.ts @@ -2,6 +2,7 @@ import _ from 'lodash' import { TabsNavItem } from '~/libs/ui' import { + assistantsRouteId, flexiTalentRouteId, showcaseSearchRouteId, skillStatisticsRouteId, @@ -27,6 +28,9 @@ export function getTabsConfig(userRoles: string[], isAnonymous: boolean, isUnpri }, { id: flexiTalentRouteId, title: 'Flexi-Talent', + }, { + id: assistantsRouteId, + title: 'Assistants', }] : []), ] diff --git a/src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.module.scss b/src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.module.scss new file mode 100644 index 000000000..694465ffc --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.module.scss @@ -0,0 +1,82 @@ +@import '@libs/ui/styles/includes'; + +.wrap { + background-color: $tc-white; + border: 1px solid $black-10; + border-radius: 16px; + display: flex; + align-items: stretch; + color: $black-100; + text-decoration: none; + cursor: pointer; + overflow: hidden; + transition: box-shadow 0.15s ease, border-color 0.15s ease; + + &:hover { + border-color: $black-20; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + } + + @include ltesm { + flex-direction: column; + } +} + +.content { + display: flex; + flex-direction: column; + gap: 8px; + padding: $sp-6; + flex: 1 1 auto; + min-width: 0; +} + +.title { + color: $black-100; + font-feature-settings: 'liga' off, 'clig' off; + font-size: 22px; + font-style: normal; + font-weight: 800; + line-height: 28px; + margin: 0; + text-transform: none; +} + +.description { + color: #545f71; + font-size: 14px; + font-weight: 400; + line-height: 22px; + margin: 0; +} + +.agentRail { + display: flex; + flex: 0 0 104px; + align-items: center; + justify-content: center; + padding: $sp-4; + background-color: $black-5; + border-left: 1px solid $black-10; + + @include ltesm { + flex: 0 0 auto; + border-left: none; + border-top: 1px solid $black-10; + } +} + +.iconBadge { + display: flex; + align-items: center; + justify-content: center; + padding: $sp-3; + border-radius: 50%; + background-color: $tc-white; +} + +.icon { + width: 24px; + height: 24px; + color: $blue-110; +} diff --git a/src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.tsx b/src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.tsx new file mode 100644 index 000000000..c7085041c --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/AssistantCard/AssistantCard.tsx @@ -0,0 +1,32 @@ +import { ComponentType, FC, SVGProps } from 'react' +import { Link } from 'react-router-dom' + +import styles from './AssistantCard.module.scss' + +interface AssistantCardProps { + title: string + description: string + icon: ComponentType> + to: string +} + +const AssistantCard: FC = props => { + const Icon = props.icon + + return ( + +
      +

      {props.title}

      +

      {props.description}

      +
      + +
      + + +
      + + ) +} + +export default AssistantCard diff --git a/src/apps/customer-portal/src/pages/assistants/AssistantCard/index.ts b/src/apps/customer-portal/src/pages/assistants/AssistantCard/index.ts new file mode 100644 index 000000000..b45588609 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/AssistantCard/index.ts @@ -0,0 +1 @@ +export { default as AssistantCard } from './AssistantCard' diff --git a/src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.module.scss b/src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.module.scss new file mode 100644 index 000000000..978fa6505 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.module.scss @@ -0,0 +1,37 @@ +@import '@libs/ui/styles/includes'; + +.page { + color: #0a0a0a; + display: flex; + flex-direction: column; + font-family: 'Nunito Sans', sans-serif; + padding: 8px 0 0; + + h1 { + color: #151515; + font-family: 'Figtree', sans-serif; + font-size: 32px; + font-weight: 700; + line-height: 38px; + margin-top: 20px; + text-transform: none; + } + + p { + color: #0a0a0a; + font-size: 18px; + line-height: 25px; + margin: 4px 0 0; + } +} + +.cards { + display: grid; + gap: 16px; + grid-template-columns: repeat(2, 1fr); + margin-top: 24px; + + @include ltesm { + grid-template-columns: 1fr; + } +} diff --git a/src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.tsx b/src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.tsx new file mode 100644 index 000000000..14fdd3123 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/AssistantsPage/AssistantsPage.tsx @@ -0,0 +1,28 @@ +import { FC } from 'react' + +import { AssistantCard } from '../AssistantCard' +import { assistantsConfig } from '../config/assistants-config' +import { assistantsRootRoute } from '../assistants.routes' + +import styles from './AssistantsPage.module.scss' + +const AssistantsPage: FC = () => ( +
      +

      Assistants

      +

      Get assistance from Topcoder AI.

      + +
      + {assistantsConfig.map(assistant => ( + + ))} +
      +
      +) + +export default AssistantsPage diff --git a/src/apps/customer-portal/src/pages/assistants/AssistantsPage/index.ts b/src/apps/customer-portal/src/pages/assistants/AssistantsPage/index.ts new file mode 100644 index 000000000..17958db34 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/AssistantsPage/index.ts @@ -0,0 +1 @@ +export { default as AssistantsPage } from './AssistantsPage' diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.module.scss b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.module.scss new file mode 100644 index 000000000..d1943a493 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.module.scss @@ -0,0 +1,81 @@ +@import '@libs/ui/styles/includes'; + +.page { + color: #0a0a0a; + display: flex; + flex-direction: column; + font-family: 'Nunito Sans', sans-serif; + padding: 8px 0 0; + + h1 { + color: #151515; + font-family: 'Figtree', sans-serif; + font-size: 32px; + font-weight: 700; + line-height: 38px; + margin-top: 20px; + text-transform: none; + } +} + +.subtitle { + color: #0a0a0a; + font-size: 18px; + line-height: 25px; + margin: 4px 0 0; +} + +.status { + color: #545f71; + font-size: 14px; + padding: 16px 0; +} + +.layout { + display: flex; + gap: 16px; + height: 70vh; + margin-top: 20px; + margin-bottom: 28px; + min-height: 480px; + width: 100%; + + @include ltesm { + flex-direction: column; + height: auto; + } +} + +.sidebar { + flex: 0 0 133px; + max-width: 133px; + + @include ltesm { + flex: 0 0 auto; + max-height: 160px; + max-width: 100%; + } +} + +.chatPanel { + display: flex; + flex: 1 1 auto; + min-width: 0; + position: relative; + width: 100%; +} + +.loadingOverlay { + align-items: center; + background-color: rgba(255, 255, 255, 0.7); + border-radius: 16px; + bottom: 0; + color: #545f71; + display: flex; + font-size: 14px; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.tsx b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.tsx new file mode 100644 index 000000000..5ceff6dbc --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/TopScoutPage.tsx @@ -0,0 +1,123 @@ +import { FC, useCallback, useContext, useEffect, useMemo, useState } from 'react' +import { UIMessage } from 'ai' + +import { CustomerPortalAppContext } from '~/apps/customer-portal/src/lib/contexts' +import { CustomerPortalAppContextModel } from '~/apps/customer-portal/src/lib/models' + +import { ChatThread } from './components/ChatThread' +import { ThreadSidebar } from './components/ThreadSidebar' +import { ChatThreadSummary, deleteChatThread, fetchChatThreadMessages, fetchChatThreads, toChatUIMessages } from './lib' +import styles from './TopScoutPage.module.scss' + +function createThreadId(): string { + return crypto.randomUUID() +} + +const TopScoutPage: FC = () => { + const { loginUserInfo }: CustomerPortalAppContextModel = useContext(CustomerPortalAppContext) + const resourceId = useMemo( + () => (loginUserInfo?.userId ? String(loginUserInfo.userId) : undefined), + [loginUserInfo?.userId], + ) + + const [threads, setThreads] = useState([]) + const [isLoadingThreads, setIsLoadingThreads] = useState(true) + const [activeThreadId, setActiveThreadId] = useState(createThreadId) + const [initialMessages, setInitialMessages] = useState([]) + const [isLoadingMessages, setIsLoadingMessages] = useState(false) + + const refreshThreads = useCallback(async () => { + if (!resourceId) { + return + } + + try { + const fetchedThreads = await fetchChatThreads(resourceId) + setThreads(fetchedThreads) + } catch (error) { + console.error('Failed to load TopScout threads:', (error as Error).message) + } finally { + setIsLoadingThreads(false) + } + }, [resourceId]) + + useEffect(() => { + setIsLoadingThreads(true) + refreshThreads() + }, [refreshThreads]) + + const handleNewThread = useCallback(() => { + setActiveThreadId(createThreadId()) + setInitialMessages([]) + }, []) + + const handleSelectThread = useCallback(async (threadId: string) => { + setIsLoadingMessages(true) + + try { + const messages = await fetchChatThreadMessages(threadId) + setInitialMessages(toChatUIMessages(messages)) + setActiveThreadId(threadId) + } catch (error) { + console.error('Failed to load TopScout thread messages:', (error as Error).message) + } finally { + setIsLoadingMessages(false) + } + }, []) + + const handleDeleteThread = useCallback(async (threadId: string) => { + try { + await deleteChatThread(threadId) + setThreads(current => current.filter(thread => thread.id !== threadId)) + + if (threadId === activeThreadId) { + handleNewThread() + } + } catch (error) { + console.error('Failed to delete TopScout thread:', (error as Error).message) + } + }, [activeThreadId, handleNewThread]) + + return ( +
      +

      TopScout

      +

      + Describe what you're looking for — TopScout asks clarifying questions, + searches and refines on your behalf, and keeps results organized by project. +

      + + {!resourceId && ( +
      Sign in to chat with TopScout.
      + )} + + {resourceId && ( +
      +
      + +
      + +
      + + {isLoadingMessages && ( +
      Loading conversation…
      + )} +
      +
      + )} +
      + ) +} + +export default TopScoutPage diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.module.scss b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.module.scss new file mode 100644 index 000000000..3f4e3056f --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.module.scss @@ -0,0 +1,273 @@ +@import '@libs/ui/styles/includes'; + +.root { + background-color: $tc-white; + display: flex; + flex: 1 1 auto; + flex-direction: column; + height: 100%; + min-height: 0; + min-width: 0; + overflow: hidden; + width: 100%; +} + +.viewport { + display: flex; + flex: 1 1 auto; + flex-direction: column; + gap: 12px; + min-height: 0; + overflow-y: auto; + padding: $sp-6; +} + +.empty { + align-items: center; + color: #545f71; + display: flex; + flex: 1 1 auto; + flex-direction: column; + font-size: 14px; + gap: 16px; + justify-content: center; + text-align: center; +} + +.suggestions { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: center; + max-width: 480px; +} + +.suggestion { + background-color: $blue-15; + border: 1px solid transparent; + border-radius: 999px; + color: $blue-140; + cursor: pointer; + font-size: 13px; + font-weight: 600; + padding: 8px 14px; + + &:hover { + border-color: $blue-110; + } +} + +.userMessage, +.assistantMessage { + border-radius: 14px; + font-size: 14px; + line-height: 22px; + max-width: 75%; + padding: 10px 14px; +} + +.userMessage { + align-self: flex-end; + background-color: $blue-110; + color: $tc-white; + white-space: pre-wrap; +} + +.assistantMessage { + align-self: flex-start; + background-color: $black-5; + color: $black-100; +} + +.toolCall { + background-color: $tc-white; + border: 1px solid $black-10; + border-radius: 10px; + margin: 4px 0 16px; + overflow: hidden; + white-space: normal; +} + +.toolCallHeader { + align-items: center; + background-color: $blue-10; + cursor: pointer; + display: flex; + gap: 8px; + list-style: none; + padding: 6px 10px; + user-select: none; + + &::-webkit-details-marker { + display: none; + } + + &::marker { + content: ''; + } +} + +.toolCallChevron { + color: $blue-120; + flex: 0 0 auto; + height: 14px; + transition: transform 0.15s ease; + width: 14px; + + .toolCall[open] & { + transform: rotate(180deg); + } +} + +.toolCallName { + color: $blue-140; + flex: 1 1 auto; + font-family: 'Roboto Mono', monospace; + font-size: 12px; + font-weight: 700; +} + +.toolCallStatus { + align-items: center; + color: $blue-120; + display: inline-flex; + font-size: 11px; + font-weight: 600; + gap: 5px; + letter-spacing: 0.02em; + text-transform: uppercase; +} + +.toolCallDots { + .thinkingDot { + background-color: currentcolor; + height: 3px; + width: 3px; + } +} + +.thinking { + padding: 12px 14px; +} + +.thinkingDots { + align-items: center; + display: inline-flex; + gap: 4px; +} + +.thinkingDot { + animation: thinkingBounce 1.2s ease-in-out infinite; + background-color: $black-40; + border-radius: 50%; + height: 6px; + width: 6px; + + &:nth-child(2) { + animation-delay: 0.15s; + } + + &:nth-child(3) { + animation-delay: 0.3s; + } +} + +@keyframes thinkingBounce { + 0%, + 60%, + 100% { + opacity: 0.35; + transform: translateY(0); + } + + 30% { + opacity: 1; + transform: translateY(-3px); + } +} + +.toolCallError { + color: $red-120; +} + +.toolCallSection { + border-top: 1px solid $black-10; + padding: 8px 10px; +} + +.toolCallLabel { + color: #545f71; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.04em; + margin-bottom: 4px; + text-transform: uppercase; +} + +.toolCallBody { + font-family: 'Roboto Mono', monospace; + font-size: 12px; + line-height: 18px; + margin: 0; + max-height: 240px; + overflow: auto; + white-space: pre; +} + +.composer { + align-items: flex-end; + border-top: 1px solid $black-10; + display: flex; + flex: 0 0 auto; + gap: 8px; + padding: $sp-4; +} + +.memoryHint { + color: $black-40; + flex: 0 0 auto; + font-size: 11px; + margin: 0; + padding: 0 $sp-4 $sp-3; + text-align: right; +} + +.input { + background-color: $tc-white; + border: 1px solid $black-20; + border-radius: 10px; + color: $black-100; + flex: 1 1 auto; + font-family: 'Nunito Sans', sans-serif; + font-size: 14px; + max-height: 120px; + padding: 10px 12px; + resize: none; + + &:focus { + border-color: $blue-110; + outline: none; + } +} + +.send, +.cancel { + background-color: $blue-110; + border: none; + border-radius: 10px; + color: $tc-white; + cursor: pointer; + flex: 0 0 auto; + font-size: 14px; + font-weight: 600; + padding: 10px 18px; + + &:disabled { + background-color: $black-20; + cursor: not-allowed; + } +} + +.cancel { + background-color: $black-60; +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.tsx b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.tsx new file mode 100644 index 000000000..e1d29bc6a --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/ChatThread.tsx @@ -0,0 +1,238 @@ +import { DefaultChatTransport, UIMessage } from 'ai' +import { FC, useCallback, useMemo } from 'react' +import classNames from 'classnames' + +import { useChat } from '@ai-sdk/react' +import { + AssistantRuntimeProvider, + ComposerPrimitive, + MessagePrimitive, + ThreadPrimitive, + type ToolCallMessagePartProps, +} from '@assistant-ui/react' +import { useAISDKRuntime } from '@assistant-ui/react-ai-sdk' +import { IconOutline } from '~/libs/ui' + +import { authFetch, CHAT_ENDPOINT_URL } from '../../lib' + +import MarkdownText from './MarkdownText' +import styles from './ChatThread.module.scss' + +const SUGGESTIONS: ReadonlyArray<{ label: string; prompt: string }> = [ + { + label: 'Help me figure it out', + prompt: "I want to find a challenge to work on but I'm not sure what yet — can you help me figure it out?", + }, + { + label: 'Real-time chat feature', + prompt: 'Find a challenge involving a real-time chat feature with websockets.', + }, + { + label: 'Design track only Figma', + prompt: 'Show me challenges on the Design track only which use Figma.', + }, +] + +// Matches `lastMessages` on the challengeSearchAgent's Memory config +// (tc-ai-api/src/mastra/agents/challenge/challenge-search-agent.ts). +const MEMORY_MESSAGE_LIMIT = 25 + +interface ChatThreadProps { + threadId: string + resourceId: string + initialMessages: UIMessage[] + onThreadActivity?: () => void | Promise +} + +function formatJson(value: unknown): string { + if (value === undefined) { + return '' + } + + try { + return JSON.stringify(value, undefined, 2) + } catch { + return String(value) + } +} + +interface ThinkingDotsProps { + className?: string +} + +const ThinkingDots: FC = props => ( + + + + + +) + +const ToolCallView: FC = props => { + const isRunning = !props.isError && props.result === undefined + const statusLabel = props.isError + ? 'Error' + : props.result !== undefined + ? 'Complete' + : 'Running' + + return ( +
      + + + {props.toolName} + + {statusLabel} + {isRunning && } + + + +
      +
      Input
      +
      +                    {formatJson(props.args)}
      +                
      +
      + + {props.result !== undefined && ( +
      +
      Output
      +
      +                        {formatJson(props.result)}
      +                    
      +
      + )} +
      + ) +} + +const UserMessage: FC = () => ( + <> + + + + + +
      + +
      +
      +
      + +) + +const AssistantMessage: FC = () => ( + + + + + + + + +) + +const ChatThread: FC = props => { + const transport = useMemo( + () => new DefaultChatTransport({ + api: CHAT_ENDPOINT_URL, + body: { + memory: { + resource: props.resourceId, + thread: props.threadId, + }, + }, + fetch: authFetch, + }), + [props.resourceId, props.threadId], + ) + + const handleFinish = useCallback(() => { + props.onThreadActivity?.() + }, [props.onThreadActivity]) + + const chat = useChat({ + id: props.threadId, + messages: props.initialMessages, + onFinish: handleFinish, + transport, + }) + + const runtime = useAISDKRuntime(chat) + + return ( + + + + +
      +

      Hello from TopScout 👋🏻

      +

      + Ask TopScout to find challenges by skill, track, + type, and/or query in natural language. +

      + +
      + {SUGGESTIONS.map(suggestion => ( + + {suggestion.label} + + ))} +
      +
      +
      + + +
      + + + + + + Send + + + + + Stop + + + + +

      + TopScout only remembers the last + {' '} + {MEMORY_MESSAGE_LIMIT} + {' '} + messages + in this conversation — earlier messages are no longer visible to it. +

      +
      +
      + ) +} + +export default ChatThread diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.module.scss b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.module.scss new file mode 100644 index 000000000..c01661c5b --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.module.scss @@ -0,0 +1,132 @@ +@import '@libs/ui/styles/includes'; + +.markdown { + > :first-child { + margin-top: 0; + } + + > :last-child { + margin-bottom: 0; + } + + p { + line-height: 22px; + margin: 0 0 10px; + } + + strong { + font-weight: 700; + } + + em { + font-style: italic; + } + + ul, + ol { + margin: 0 0 10px; + padding-left: 20px; + } + + li { + line-height: 22px; + margin-bottom: 2px; + } + + li > ul, + li > ol { + margin-top: 2px; + margin-bottom: 2px; + } + + hr { + border: none; + border-top: 1px solid $black-20; + margin: 12px 0; + } + + a { + color: $blue-140; + font-weight: 600; + text-decoration: underline; + text-underline-offset: 2px; + + &:hover { + color: $blue-160; + } + } + + code { + background-color: $black-10; + border-radius: 4px; + font-family: 'Roboto Mono', monospace; + font-size: 12px; + padding: 1px 4px; + } + + pre { + background-color: $black-10; + border-radius: 8px; + margin: 0 0 10px; + overflow-x: auto; + padding: 10px 12px; + + code { + background-color: transparent; + padding: 0; + } + } + + blockquote { + border-left: 3px solid $black-20; + color: #545f71; + margin: 0 0 10px; + padding-left: 10px; + } + + table { + border-collapse: collapse; + display: block; + margin: 0 0 10px; + overflow-x: auto; + width: 100%; + } + + th, + td { + border: 1px solid $black-20; + padding: 4px 8px; + text-align: left; + } + + th { + background-color: $black-5; + font-weight: 700; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + font-weight: 700; + line-height: 1.3; + margin: 12px 0 6px; + } + + h1 { + font-size: 18px; + } + + h2 { + font-size: 16px; + } + + h3, + h4, + h5, + h6 { + font-size: 14px; + } +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.tsx b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.tsx new file mode 100644 index 000000000..64dcdb56f --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/MarkdownText.tsx @@ -0,0 +1,32 @@ +import { AnchorHTMLAttributes, FC } from 'react' +import remarkGfm from 'remark-gfm-v4' + +import { MarkdownTextPrimitive } from '@assistant-ui/react-markdown' + +import styles from './MarkdownText.module.scss' + +// remark-gfm-v4 is aliased to remark-gfm@4 (see package.json) instead of the +// shared `remark-gfm@^3.0.1` top-level pin: @assistant-ui/react-markdown +// vendors its own react-markdown@10/unified@11 pipeline, which remark-gfm@3 +// (built for unified@9/10) isn't guaranteed to parse tables correctly +// against. The alias resolves to an isolated nested install, so this +// doesn't touch the v3 pin other apps' markdown pipelines (engagements, +// profiles, support) rely on. + +// Every link the agent renders (challenge titles included) should open in a +// new tab rather than navigate away from the chat. +const MarkdownLink: FC> = props => ( +
      + {props.children} + +) + +const MarkdownText: FC = () => ( + +) + +export default MarkdownText diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/index.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/index.ts new file mode 100644 index 000000000..b80ae732a --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ChatThread/index.ts @@ -0,0 +1 @@ +export { default as ChatThread } from './ChatThread' diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.module.scss b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.module.scss new file mode 100644 index 000000000..88db56ef0 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.module.scss @@ -0,0 +1,108 @@ +@import '@libs/ui/styles/includes'; + +.wrap { + background-color: $black-5; + border: 1px solid $black-10; + border-radius: 10px; + display: flex; + flex-direction: column; + gap: 4px; + height: 100%; + overflow: hidden; + padding: 6px; +} + +.newThread { + align-items: center; + background-color: $blue-110; + border: none; + border-radius: 6px; + color: $tc-white; + cursor: pointer; + display: flex; + flex: 0 0 auto; + font-size: 12px; + font-weight: 600; + gap: 4px; + justify-content: center; + padding: 6px 8px; +} + +.newThreadIcon { + height: 13px; + width: 13px; +} + +.status { + color: #545f71; + font-size: 12px; + padding: 6px 4px; +} + +.list { + display: flex; + flex: 1 1 auto; + flex-direction: column; + gap: 2px; + list-style: none; + margin: 0; + overflow-y: auto; + padding: 0; +} + +.threadItem { + align-items: center; + border-radius: 8px; + display: flex; + gap: 2px; + + &:hover { + background-color: $black-10; + } + + &.active { + background-color: $blue-15; + } +} + +.selectButton { + background: none; + border: none; + color: $black-100; + cursor: pointer; + flex: 1 1 auto; + min-width: 0; + padding: 5px 0 5px 5px; + text-align: left; +} + +.threadTitle { + display: block; + font-size: 11px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.deleteButton { + align-items: center; + background: none; + border: none; + border-radius: 5px; + cursor: pointer; + display: flex; + flex: 0 0 auto; + justify-content: center; + margin-right: 1px; + padding: 3px; + + &:hover { + background-color: $black-20; + } +} + +.deleteIcon { + color: $black-60; + height: 11px; + width: 11px; +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.tsx b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.tsx new file mode 100644 index 000000000..44aa48fa4 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/ThreadSidebar.tsx @@ -0,0 +1,125 @@ +import { FC, MouseEvent, useCallback } from 'react' +import classNames from 'classnames' + +import { IconOutline } from '~/libs/ui' + +import { ChatThreadSummary } from '../../lib' + +import styles from './ThreadSidebar.module.scss' + +const threadDateFormatter = new Intl.DateTimeFormat('en-US', { + day: 'numeric', + hour: 'numeric', + minute: '2-digit', + month: 'short', +}) + +function getThreadDisplayTitle(thread: ChatThreadSummary): string { + const title = thread.title?.trim() + + if (title) { + return title + } + + const threadDate = new Date(thread.updatedAt || thread.createdAt) + + if (Number.isNaN(threadDate.getTime())) { + return 'Untitled thread' + } + + return threadDateFormatter.format(threadDate) +} + +interface ThreadSidebarProps { + threads: ChatThreadSummary[] + activeThreadId: string + isLoading: boolean + onSelect: (threadId: string) => void | Promise + onNew: () => void + onDelete: (threadId: string) => void | Promise +} + +const ThreadSidebar: FC = props => { + const handleSelectClick = useCallback( + (event: MouseEvent) => { + const { threadId }: { threadId?: string } + = event.currentTarget.dataset + + if (threadId) { + props.onSelect(threadId) + } + }, + [props], + ) + + const handleDeleteClick = useCallback( + (event: MouseEvent) => { + event.stopPropagation() + const { threadId }: { threadId?: string } + = event.currentTarget.dataset + + if (threadId) { + props.onDelete(threadId) + } + }, + [props], + ) + + return ( +
      + + + {props.isLoading && ( +
      Loading threads…
      + )} + + {!props.isLoading && ( +
        + {props.threads.map(thread => ( +
      • + + +
      • + ))} +
      + )} +
      + ) +} + +export default ThreadSidebar diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/index.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/index.ts new file mode 100644 index 000000000..5041802e8 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/components/ThreadSidebar/index.ts @@ -0,0 +1 @@ +export { default as ThreadSidebar } from './ThreadSidebar' diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/index.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/index.ts new file mode 100644 index 000000000..a50eed7bc --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/index.ts @@ -0,0 +1 @@ +export { default as TopScoutPage } from './TopScoutPage' diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/auth-fetch.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/auth-fetch.ts new file mode 100644 index 000000000..05593d7f6 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/auth-fetch.ts @@ -0,0 +1,18 @@ +import { tokenGetAsync, TokenModel } from '~/libs/core' + +/** + * `ai`'s DefaultChatTransport uses raw `fetch`, bypassing the axios instance + * (and its auth interceptor) the rest of the app relies on — so the bearer + * token is attached here instead, refetched per request the same way + * `interceptAuth` does for axios. + */ +export const authFetch: typeof fetch = async (input, init) => { + const tokenData: TokenModel = await tokenGetAsync() + const headers = new Headers(init?.headers) + + if (tokenData.token) { + headers.set('Authorization', `Bearer ${tokenData.token}`) + } + + return fetch(input, { ...init, headers }) +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/chat.service.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/chat.service.ts new file mode 100644 index 000000000..5ef5be321 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/chat.service.ts @@ -0,0 +1,39 @@ +import { xhrDeleteAsync, xhrGetAsync } from '~/libs/core' + +import { + CHALLENGE_SEARCH_AGENT_ID, + getMemoryThreadMessagesUrl, + getMemoryThreadUrl, + MEMORY_THREADS_URL, +} from './constants' +import { + ChatThreadSummary, + ListChatThreadMessagesResponse, + ListChatThreadsResponse, + StoredMessage, +} from './models' + +export async function fetchChatThreads(resourceId: string): Promise { + const query = new URLSearchParams({ + agentId: CHALLENGE_SEARCH_AGENT_ID, + resourceId, + }) + + const response = await xhrGetAsync( + `${MEMORY_THREADS_URL}?${query.toString()}`, + ) + + return response.threads ?? [] +} + +export async function fetchChatThreadMessages(threadId: string): Promise { + const response = await xhrGetAsync( + getMemoryThreadMessagesUrl(threadId), + ) + + return response.messages ?? [] +} + +export async function deleteChatThread(threadId: string): Promise { + await xhrDeleteAsync(getMemoryThreadUrl(threadId)) +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/constants.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/constants.ts new file mode 100644 index 000000000..55c4e9eb0 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/constants.ts @@ -0,0 +1,28 @@ +import { EnvironmentConfig } from '~/config' + +/** + * Matches the AGENT_ID registered on `challengeSearchAgent` in tc-ai-api + * (src/mastra/agents/challenge/challenge-search-agent.ts) — Mastra resolves + * agents by this id first, before falling back to the registry key. + */ +export const CHALLENGE_SEARCH_AGENT_ID = 'challenge-search-agent' + +// The load balancer only forwards `/v6/ai/*` to tc-ai-api. Mastra's built-in +// routes (memory/threads included) live under its configured apiPrefix, +// `/v6/ai/api`; the chat route is a custom route registered as a sibling +// under `/v6/ai/chat` instead, since Mastra reserves apiPrefix exclusively +// for built-ins (see tc-ai-api's src/utils/server-routes.ts). +const LB_ROUTE_CHAT = `${EnvironmentConfig.API.V6}/ai-chat` +const BUILTIN_API_BASE_URL = `${EnvironmentConfig.API.V6}/ai` + +export const CHAT_ENDPOINT_URL = `${LB_ROUTE_CHAT}/${CHALLENGE_SEARCH_AGENT_ID}` + +export const MEMORY_THREADS_URL = `${BUILTIN_API_BASE_URL}/memory/threads` + +export function getMemoryThreadMessagesUrl(threadId: string): string { + return `${BUILTIN_API_BASE_URL}/memory/threads/${threadId}/messages?agentId=${CHALLENGE_SEARCH_AGENT_ID}` +} + +export function getMemoryThreadUrl(threadId: string): string { + return `${BUILTIN_API_BASE_URL}/memory/threads/${threadId}?agentId=${CHALLENGE_SEARCH_AGENT_ID}` +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/convert-messages.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/convert-messages.ts new file mode 100644 index 000000000..8748210fc --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/convert-messages.ts @@ -0,0 +1,111 @@ +import { UIMessage } from 'ai' + +import { StoredMessage } from './models' + +/** + * Mastra persists messages in its own legacy (AI SDK v4-shaped) format: + * `{ type: 'tool-invocation', toolInvocation: { toolCallId, toolName, args, + * state, result, isError } }`. `ai` v7's UIMessage tool parts use a flatter, + * differently-named shape (`input`/`output`/`state` at the top level), so + * without translation these parts fail to parse — the tool-call card falls + * back to a generic "invocation" name, an empty input, and a stuck + * "running" status. This maps the legacy shape into a v7 `dynamic-tool` part. + */ +interface LegacyToolInvocation { + toolCallId: string + toolName: string + args?: unknown + state: + | 'partial-call' + | 'call' + | 'result' + | 'approval-requested' + | 'approval-responded' + | 'output-error' + | 'output-denied' + result?: unknown + isError?: boolean +} + +interface LegacyToolInvocationPart { + type: 'tool-invocation' + toolInvocation: LegacyToolInvocation + [key: string]: unknown +} + +function isLegacyToolInvocationPart(part: Record): part is LegacyToolInvocationPart { + return part.type === 'tool-invocation' + && typeof part.toolInvocation === 'object' + && part.toolInvocation !== null +} + +function errorTextFrom(result: unknown): string { + return typeof result === 'string' ? result : 'Tool call failed' +} + +function toDynamicToolPart(part: LegacyToolInvocationPart): Record { + const invocation = part.toolInvocation + const base = { + toolCallId: invocation.toolCallId, + toolName: invocation.toolName, + type: 'dynamic-tool', + } + + switch (invocation.state) { + case 'partial-call': + return { ...base, input: invocation.args, state: 'input-streaming' } + case 'call': + case 'approval-requested': + case 'approval-responded': + // Our tools never require approval — fold those states into the + // plain "waiting on the tool" state rather than fabricate an + // `approval` object the source data doesn't have. + return { ...base, input: invocation.args, state: 'input-available' } + case 'output-error': + case 'output-denied': + return { + ...base, + errorText: errorTextFrom(invocation.result), + input: invocation.args, + state: 'output-error', + } + case 'result': + default: + return invocation.isError + ? { + ...base, + errorText: errorTextFrom(invocation.result), + input: invocation.args, + state: 'output-error', + } + : { + ...base, + input: invocation.args, + output: invocation.result, + state: 'output-available', + } + } +} + +function normalizeStoredPart(part: Record): Record { + return isLegacyToolInvocationPart(part) ? toDynamicToolPart(part) : part +} + +/** + * Converts persisted Memory messages into `ai` UIMessages for display. + * Every part — text as well as the agent's tool calls (challengeVectorQueryTool, + * fetchProjectTool) with their input/output — is carried through, so + * reopening a thread shows the same tool-call visibility a live run does. + */ +export function toChatUIMessages(messages: StoredMessage[]): UIMessage[] { + return messages + .filter((message): message is StoredMessage & { role: 'user' | 'assistant' } => ( + message.role === 'user' || message.role === 'assistant' + )) + .map(message => ({ + id: message.id, + parts: (message.content.parts ?? []).map(normalizeStoredPart) as UIMessage['parts'], + role: message.role, + })) + .filter(message => message.parts.length > 0) +} diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/index.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/index.ts new file mode 100644 index 000000000..2c1b1b5b5 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/index.ts @@ -0,0 +1,5 @@ +export * from './auth-fetch' +export * from './chat.service' +export * from './constants' +export * from './convert-messages' +export * from './models' diff --git a/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/models.ts b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/models.ts new file mode 100644 index 000000000..f9fdcd5e3 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/TopScoutPage/lib/models.ts @@ -0,0 +1,26 @@ +export interface ChatThreadSummary { + id: string + resourceId: string + title?: string + createdAt: string + updatedAt: string +} + +export interface ListChatThreadsResponse { + threads: ChatThreadSummary[] +} + +export interface StoredMessage { + id: string + role: 'user' | 'assistant' | 'system' + content: { + // Text, tool-call, reasoning, etc. — passed through as stored so + // tool-call input/output stay visible on thread reload; shaped to + // match `ai`'s UIMessage parts by construction on the server side. + parts?: Array> + } +} + +export interface ListChatThreadMessagesResponse { + messages: StoredMessage[] +} diff --git a/src/apps/customer-portal/src/pages/assistants/assistants.routes.tsx b/src/apps/customer-portal/src/pages/assistants/assistants.routes.tsx new file mode 100644 index 000000000..62b6e2c89 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/assistants.routes.tsx @@ -0,0 +1,41 @@ +import { getRoutesContainer, lazyLoad, LazyLoadedComponent } from '~/libs/core' + +import { assistantsRouteId, rootRoute, topScoutRouteId } from '../../config/routes.config' + +const AssistantsPage: LazyLoadedComponent = lazyLoad( + () => import('./AssistantsPage'), + 'AssistantsPage', +) + +const TopScoutPage: LazyLoadedComponent = lazyLoad( + () => import('./TopScoutPage'), + 'TopScoutPage', +) + +export const assistantsRootRoute = `${rootRoute}/${assistantsRouteId}` + +export const getTopScoutRoute = (): string => `${assistantsRootRoute}/${topScoutRouteId}` + +export const assistantsChildRoutes = [ + { + authRequired: true, + element: , + id: 'assistants-page', + route: '', + }, + { + authRequired: true, + element: , + id: 'top-scout-page', + route: topScoutRouteId, + }, +] + +export const customerPortalAssistantsRoutes = [ + { + children: [...assistantsChildRoutes], + element: getRoutesContainer(assistantsChildRoutes), + id: assistantsRouteId, + route: assistantsRouteId, + }, +] diff --git a/src/apps/customer-portal/src/pages/assistants/config/assistants-config.ts b/src/apps/customer-portal/src/pages/assistants/config/assistants-config.ts new file mode 100644 index 000000000..3c6bc7a26 --- /dev/null +++ b/src/apps/customer-portal/src/pages/assistants/config/assistants-config.ts @@ -0,0 +1,22 @@ +import { ComponentType, SVGProps } from 'react' + +import { IconOutline } from '~/libs/ui' +import { topScoutRouteId } from '~/apps/customer-portal/src/config/routes.config' + +export interface AssistantConfigItem { + id: string + title: string + description: string + icon: ComponentType> +} + +export const assistantsConfig: AssistantConfigItem[] = [ + { + description: 'Challenge-driven search and navigation. Filter by technical and business ' + + 'specs at the challenge level, view parent project details, and connect with ' + + 'related engagements and members.', + icon: IconOutline.SearchIcon, + id: topScoutRouteId, + title: 'TopScout', + }, +] diff --git a/src/config/environments/default.env.ts b/src/config/environments/default.env.ts index 960b209c2..2ef40bea9 100644 --- a/src/config/environments/default.env.ts +++ b/src/config/environments/default.env.ts @@ -267,6 +267,11 @@ export const SKILLS_EXTRACTION_WORKFLOW_ID = getReactEnv( 'skillExtractionWorkflow', ) +export const RAG_CHALLENGE_INGESTION_WORKFLOW_ID = getReactEnv( + 'RAG_CHALLENGE_INGESTION_WORKFLOW_ID', + 'challengeIngestionWorkflow', +) + export const ADMIN = { AGREE_ELECTRONICALLY: '5b2798b2-ae82-4210-9b4d-5d6428125ccb', AGREE_FOR_DOCUSIGN_TEMPLATE: '999a26ad-b334-453c-8425-165d4cf496d7', diff --git a/src/config/environments/global-config.model.ts b/src/config/environments/global-config.model.ts index a94d2544b..5e6950bce 100644 --- a/src/config/environments/global-config.model.ts +++ b/src/config/environments/global-config.model.ts @@ -115,6 +115,7 @@ export interface GlobalConfig { PROGRESS_INTERVAL: number }, SKILLS_EXTRACTION_WORKFLOW_ID: string + RAG_CHALLENGE_INGESTION_WORKFLOW_ID: string ADMIN_SSO_LOGIN_PROVIDERS: SSOLoginProviderConfig[] LOCAL_SERVICE_OVERRIDES?: LocalServiceOverride[] TROLLEY_WIDGET_ORIGIN: string diff --git a/src/libs/shared/lib/services/ai-workflows.tsx b/src/libs/shared/lib/services/ai-workflows.tsx index fadb949a3..b3711e990 100644 --- a/src/libs/shared/lib/services/ai-workflows.tsx +++ b/src/libs/shared/lib/services/ai-workflows.tsx @@ -11,7 +11,7 @@ interface WorkflowRunResponse { } interface WorkflowInputData { - inputData: { jobDescription: string } + inputData: Record } const sleep = (ms: number): Promise => new Promise(resolve => { @@ -22,10 +22,11 @@ const sleep = (ms: number): Promise => new Promise(resolve => { * Start an AI workflow run * * @param workflowId - The ID of the workflow to run - * @param input - The input data for the workflow + * @param inputData - The input data for the workflow, shaped to match that + * workflow's own input schema * @returns The run ID */ -async function startWorkflowRun(workflowId: string, input: string): Promise { +async function startWorkflowRun(workflowId: string, inputData: Record): Promise { try { // Step 1: Create the run @@ -42,7 +43,7 @@ async function startWorkflowRun(workflowId: string, input: string): Promise( `${API_BASE_URL}/workflows/${workflowId}/start?runId=${runId}`, - { inputData: { jobDescription: input } }, + { inputData }, ) return runId @@ -246,7 +247,7 @@ export async function extractSkillsFromText( try { // Step 1: Start the workflow run console.log(`Starting workflow run for: ${workflowIdToUse}`) - const runId = await startWorkflowRun(workflowIdToUse, description) + const runId = await startWorkflowRun(workflowIdToUse, { jobDescription: description }) console.log(`Workflow started with runId: ${runId}`) // Step 2: Poll for completion @@ -260,3 +261,62 @@ export async function extractSkillsFromText( throw error } } + +export interface ChallengeIngestionResult { + chunks: number + dryRun: boolean + skipped: boolean + projectId: string | undefined +} + +function normalizeChallengeIngestionResult(result: WorkflowRunResult): ChallengeIngestionResult { + const raw = (result?.result ?? {}) as Record + + return { + chunks: typeof raw.chunks === 'number' ? raw.chunks : 0, + dryRun: Boolean(raw.dryRun), + projectId: typeof raw.projectId === 'string' ? raw.projectId : undefined, + skipped: Boolean(raw.skipped), + } +} + +/** + * Ingest a single challenge into the RAG vector index using AI workflow + * + * @example + * try { + * const report = await ingestChallengeInRag('a1b2c3d4-...') + * console.log('Ingested chunks:', report.chunks) + * } catch (error) { + * console.error('Challenge ingestion failed:', error.message) + * } + */ +export async function ingestChallengeInRag( + challengeId: string, + workflowId?: string, +): Promise { + if (!challengeId || typeof challengeId !== 'string') { + throw new Error('Challenge id must be a non-empty string') + } + + const workflowIdToUse = workflowId || EnvironmentConfig.RAG_CHALLENGE_INGESTION_WORKFLOW_ID + + if (!workflowIdToUse) { + throw new Error('RAG Challenge Ingestion Workflow ID is not configured') + } + + try { + console.log(`Starting workflow run for: ${workflowIdToUse}`) + const runId = await startWorkflowRun(workflowIdToUse, { challengeId }) + console.log(`Workflow started with runId: ${runId}`) + + console.log('Polling for workflow completion...') + const result = await pollWorkflowRunStatus(workflowIdToUse, runId) + console.log('Workflow completed successfully') + + return normalizeChallengeIngestionResult(result) + } catch (error) { + console.error('Challenge RAG ingestion workflow failed:', (error as Error).message) + throw error + } +} diff --git a/tsconfig.json b/tsconfig.json index e87786564..b266504f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.paths.json", "compilerOptions": { - "target": "es5", + "target": "es2017", "lib": [ "dom", "dom.iterable", diff --git a/yarn.lock b/yarn.lock index 80221ed84..f758da089 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,55 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.4.tgz#2856c55443d3d461693f32d2b96fb6ea92e1ffa9" integrity sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg== +"@ai-sdk/gateway@4.0.64": + version "4.0.64" + resolved "https://registry.yarnpkg.com/@ai-sdk/gateway/-/gateway-4.0.64.tgz#29e87186fb3826105d0371d6c70f461b0e9e9bf3" + integrity sha512-iayK1z11I0b3sgbP3j6eKQypfpwO5Fbtaq1Mkwv7YxwGQG1YTNr5QAjyYsSfqyf/58WUOLWz2cTBpk+ExZVgpw== + dependencies: + "@ai-sdk/provider" "4.0.8" + "@ai-sdk/provider-utils" "5.0.30" + "@vercel/oidc" "3.2.0" + +"@ai-sdk/mcp@2.0.37", "@ai-sdk/mcp@^2.0.32": + version "2.0.37" + resolved "https://registry.yarnpkg.com/@ai-sdk/mcp/-/mcp-2.0.37.tgz#08c71d033101bb72bdd3873a7ee0df528bf93fc3" + integrity sha512-VYmO75lhrCr9LBrUuXBpS/cMJ/KL1YhLo7nGgLTqOKtXA3+9kIY73gJmzg/GIANyGVatffrGER43iIFFlqUxtA== + dependencies: + "@ai-sdk/provider" "4.0.8" + "@ai-sdk/provider-utils" "5.0.30" + cross-spawn "^7.0.6" + pkce-challenge "^5.0.1" + +"@ai-sdk/provider-utils@5.0.30": + version "5.0.30" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-5.0.30.tgz#926947ffa7295b8315d0d6f66e079629c213c909" + integrity sha512-9TyxUXolql77ntHIeygLqt7PO1O0HZPB73cJhLG2OsPecSBRIZhNXLxT1T7rlL6Zpm1eDoLMFrMV99kAJ28/Sg== + dependencies: + "@ai-sdk/provider" "4.0.8" + "@standard-schema/spec" "^1.1.0" + "@workflow/serde" "4.1.0" + eventsource-parser "^3.0.8" + undici "^7.28.0" + +"@ai-sdk/provider@4.0.8": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-4.0.8.tgz#d3f6c72db71098363e18c2e384945fbc7a983c19" + integrity sha512-aWO7iwhFUGf347tCwNGggggfmZigaSu7TF739IZSrWWABUp7zkb4Cr3fMqvBe5EIS7ABJJu3Cadn0g/zs1G0QQ== + dependencies: + json-schema "^0.4.0" + +"@ai-sdk/react@4.0.82", "@ai-sdk/react@^4.0.69": + version "4.0.82" + resolved "https://registry.yarnpkg.com/@ai-sdk/react/-/react-4.0.82.tgz#b7ed64fb83784d32ae6f83e85c8f377e46c164e0" + integrity sha512-1zmDxOFSb2JxKovhYCHEHl/C9Nhx7PreI/FrQq1LqbA9BxGBs0xBF2MZaB7YN+h6K5XrAVgY7CzmaLB4IjA3wQ== + dependencies: + "@ai-sdk/mcp" "2.0.37" + "@ai-sdk/provider" "4.0.8" + "@ai-sdk/provider-utils" "5.0.30" + ai "7.0.79" + swr "^2.4.1" + throttleit "2.1.0" + "@alloc/quick-lru@^5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" @@ -20,6 +69,79 @@ jsonpointer "^5.0.1" leven "^3.1.0" +"@assistant-ui/ai-sdk@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@assistant-ui/ai-sdk/-/ai-sdk-0.0.2.tgz#0725110c78efe966edb1b3b2c36a23bfd9edb9d0" + integrity sha512-4mjZwR/dRVDORtIrLfK+aD3Lel/TDPlDrEaDyTjnsPYAhohNHcE9LDW4wQxcLrLQPgz6QwEPQEGwREvk7yIatA== + dependencies: + "@ai-sdk/mcp" "^2.0.32" + "@ai-sdk/react" "^4.0.69" + "@assistant-ui/core" "^0.3.15" + "@assistant-ui/store" "^0.3.10" + "@assistant-ui/tap" "^0.9.14" + ai "^7.0.66" + assistant-cloud "*" + assistant-stream "^0.3.39" + +"@assistant-ui/core@^0.3.15": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@assistant-ui/core/-/core-0.3.15.tgz#1ff869af584f557016da75e4316c9f3cc00061ad" + integrity sha512-pCeVhMmzK4xFbahtRtvjlGXDxycsvl1plgiD0M5ZyABm+QxINGnBO5GEz1hqDHQVjKlCIJDNj15PlFSkuFnidA== + dependencies: + assistant-stream "^0.3.39" + nanoid "^6.0.1" + +"@assistant-ui/react-ai-sdk@1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@assistant-ui/react-ai-sdk/-/react-ai-sdk-1.4.7.tgz#5b8d1df57d13c28b958fdbb50f3f4aea8a8bfd26" + integrity sha512-fVeJ0TzvdHwSyRt9OHqPUJEHaqORmOxj5e552N2ie6GaMuMhklSU54bzLnlEHqP2m92Ee7dFj5WwEKKckawZXQ== + dependencies: + "@assistant-ui/ai-sdk" "^0.0.2" + +"@assistant-ui/react-markdown@0.14.12": + version "0.14.12" + resolved "https://registry.yarnpkg.com/@assistant-ui/react-markdown/-/react-markdown-0.14.12.tgz#4fc13e8fe8a27f5106e836f394e2e70a0c035c1b" + integrity sha512-g8uRpTpwk43qYzknPh7k1U0FysdJ4gySY88NiBLbCRWEGy/aHPy5B+6kaRttND3Rij3rQpGkP5NZOo/z+kMEEQ== + dependencies: + "@radix-ui/react-primitive" "^2.1.10" + "@radix-ui/react-use-callback-ref" "^1.1.4" + classnames "^2.5.1" + react-markdown "^10.1.0" + +"@assistant-ui/react@0.15.16": + version "0.15.16" + resolved "https://registry.yarnpkg.com/@assistant-ui/react/-/react-0.15.16.tgz#d725c0307b4d0954c8e427b35ac545215d6bc951" + integrity sha512-+2BO6npVEXdViNWTyH3XddVXHo7SOcXliM8btrXGzH6PHuTtn3CYL7DCQ5ZXVRHB9kYPBbbMPURVu93jg9qIwg== + dependencies: + "@assistant-ui/core" "^0.3.15" + "@assistant-ui/store" "^0.3.10" + "@assistant-ui/tap" "^0.9.14" + "@radix-ui/primitive" "^1.1.7" + "@radix-ui/react-collection" "^1.1.15" + "@radix-ui/react-compose-refs" "^1.1.5" + "@radix-ui/react-context" "^1.2.2" + "@radix-ui/react-primitive" "^2.1.10" + "@radix-ui/react-use-callback-ref" "^1.1.4" + "@radix-ui/react-use-controllable-state" "^1.2.6" + "@radix-ui/react-use-escape-keydown" "^1.1.5" + assistant-cloud "^0.1.41" + assistant-stream "^0.3.39" + radix-ui "^1.6.7" + react-textarea-autosize "^8.5.9" + safe-content-frame "^0.0.27" + zod "^4.4.3" + zustand "^5.0.15" + +"@assistant-ui/store@^0.3.10": + version "0.3.10" + resolved "https://registry.yarnpkg.com/@assistant-ui/store/-/store-0.3.10.tgz#9c81560e87f547191cbbd1dbaabd0c485e510146" + integrity sha512-QSFgodFt/daEjyaY09WdahNewsGPtAeY+DkSb2LM2rPN6634h13R1vJQvCtyWK5YsI5WXgzgbsctzgpIQLU0qw== + +"@assistant-ui/tap@^0.9.14": + version "0.9.14" + resolved "https://registry.yarnpkg.com/@assistant-ui/tap/-/tap-0.9.14.tgz#a45cd18ccdbf6bac74bc711e9be611ff31270758" + integrity sha512-L/ZyXLQb51/d+/5xlXaP1197PF94EO/Ji+/CBWTjuEbsU1+8dzXCHVNO9GCFQvyG02OiOVitfbRksipMVzdrnA== + "@aw-web-design/x-default-browser@1.4.126": version "1.4.126" resolved "https://registry.yarnpkg.com/@aw-web-design/x-default-browser/-/x-default-browser-1.4.126.tgz#43e4bd8f0314ed907a8718d7e862a203af79bc16" @@ -1182,6 +1304,11 @@ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.2.tgz#9a6e2d05f4b6692e1801cd4fb176ad823930ed5e" integrity sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g== +"@babel/runtime@^7.20.13": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768" + integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw== + "@babel/template@^7.28.6", "@babel/template@^7.3.3": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" @@ -2992,6 +3119,11 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/number@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.3.tgz#9661c4bb44de93355993e1e09fed4fc8dfa9f7a6" + integrity sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA== + "@radix-ui/primitive@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd" @@ -3004,6 +3136,44 @@ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.3.tgz#e2dbc13bdc5e4168f4334f75832d7bdd3e2de5ba" integrity sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg== +"@radix-ui/primitive@1.1.7", "@radix-ui/primitive@^1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.7.tgz#0d0929d20299f60b0cd8a0deafad79f8048f9306" + integrity sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q== + +"@radix-ui/react-accessible-icon@1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.15.tgz#b6022d8ec1cad1ae499e3fb3215fe82c61b41026" + integrity sha512-WTQwcAvQf5sOcuUyi90lKPbhwcvQ+j55cjrSmeaN+L2vKU3DooOvlKw2MDeiJ5IkV5N905KW0/fGojKOBhD11A== + dependencies: + "@radix-ui/react-visually-hidden" "1.2.11" + +"@radix-ui/react-accordion@1.2.20": + version "1.2.20" + resolved "https://registry.yarnpkg.com/@radix-ui/react-accordion/-/react-accordion-1.2.20.tgz#b472f0a32028bc43e8af749169b65cbbcdfd70bf" + integrity sha512-jDhG9FvAEnlhnjrsINbNXcUa4G+L1KqSkJSunkbKEzFRcAb52jvM0PjPxPRvhe1HNc5F5yc0yzzWeeqlH4yBIg== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collapsible" "1.1.20" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + +"@radix-ui/react-alert-dialog@1.1.23": + version "1.1.23" + resolved "https://registry.yarnpkg.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.23.tgz#4e2f354a3b0209b8bdf2c6d85085a8091baa11f4" + integrity sha512-VAYOiQRqj3GPpYJE0I9J+X8Ip05cyVlNdKOFeiGS2Ou1HHGfpl0BxOyZm6nmVDyU+W+NF3/XLzmjHmVGydhwgA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dialog" "1.1.23" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-arrow@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz#c24f7968996ed934d57fe6cde5d6ec7266e1d25d" @@ -3012,6 +3182,59 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.3" +"@radix-ui/react-arrow@1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz#66658c78e9046b7f6000c1ec23d98dd80e1de58a" + integrity sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + +"@radix-ui/react-aspect-ratio@1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.15.tgz#43e6f97912febf432b81245445e20aa76933ce89" + integrity sha512-fy+dyVR+90nelK8rqIznFlxzx7uPcGbhxH8Nfr2bHb4UfSe+e3hklOC0luK0hDwVwnRX7xTRySpsrQVeW+/oNQ== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + +"@radix-ui/react-avatar@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-1.2.6.tgz#1133b4b13b15e571796d4431175114dddac3b06e" + integrity sha512-4ULOTJ/mqy2hT9GlWa/MFHxHSvH3nJzHnZM1waNsc5Bonv7i70aNenghXmD97S6OJ81ekXONGGt4nT1r0PfEdA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-is-hydrated" "0.1.3" + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-checkbox@1.3.11": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.3.11.tgz#2a7b4fb747b9b3ff3c30094b8fb95ff221c6a4b5" + integrity sha512-Gnptr9pDDQxD3hgq2dtPbtrp/c2qH1mBwIzw3X/ivrMb2e1t0jMTi606fVEqFPaQR1ggXIVQWKj3P2WW9v7zGQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-size" "1.1.4" + +"@radix-ui/react-collapsible@1.1.20": + version "1.1.20" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.1.20.tgz#146057107f01587380b6f5b0ef8f60abd7230b23" + integrity sha512-mcGesGplBnzN2sbvJETzpCNfSMyPnb29q1GRLU+Ib7bJrpIG2ywmRoh2V5VbA2uNvKikKUlVbAPks7JDjz4A8Q== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-collection@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159" @@ -3023,6 +3246,16 @@ "@radix-ui/react-primitive" "1.0.3" "@radix-ui/react-slot" "1.0.2" +"@radix-ui/react-collection@1.1.15", "@radix-ui/react-collection@^1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.15.tgz#6f045630d6f9778ab1b0c456ae97b474aec8a20b" + integrity sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA== + dependencies: + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-collection@1.1.7": version "1.1.7" resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.7.tgz#d05c25ca9ac4695cc19ba91f42f686e3ea2d9aec" @@ -3045,6 +3278,22 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz#a2c4c47af6337048ee78ff6dc0d090b390d2bb30" integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg== +"@radix-ui/react-compose-refs@1.1.5", "@radix-ui/react-compose-refs@^1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz#883e642c5ec0ba393dd1bf586e7e772985770d87" + integrity sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA== + +"@radix-ui/react-context-menu@2.3.7": + version "2.3.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-2.3.7.tgz#9973ebbccc944bd99582c60dd1e99a5bc0285c8d" + integrity sha512-CtXP35dxaB5T3zXSd+E3uHe/QpXcpYnZmxp6OaIbfthtfW4wyb77M23BG+bwIJDtsMwEP/YssdsmNyZu7jhWew== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-menu" "2.1.24" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-context@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c" @@ -3057,6 +3306,32 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.2.tgz#61628ef269a433382c364f6f1e3788a6dc213a36" integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA== +"@radix-ui/react-context@1.2.2", "@radix-ui/react-context@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.2.2.tgz#fe2548e98465f5f9b776c5953de35d04a8919b6b" + integrity sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA== + +"@radix-ui/react-dialog@1.1.23": + version "1.1.23" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz#b7d8e83a3ccf97e46f3c3f477a0bf563f0de8239" + integrity sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + aria-hidden "^1.2.4" + react-remove-scroll "^2.7.2" + "@radix-ui/react-direction@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b" @@ -3069,6 +3344,11 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.1.tgz#39e5a5769e676c753204b792fbe6cf508e550a14" integrity sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw== +"@radix-ui/react-direction@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.4.tgz#e7b7049f3c3ab8e6e014c4600f9f1974a52c05f1" + integrity sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg== + "@radix-ui/react-dismissable-layer@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz#883a48f5f938fa679427aa17fcba70c5494c6978" @@ -3081,6 +3361,30 @@ "@radix-ui/react-use-callback-ref" "1.0.1" "@radix-ui/react-use-escape-keydown" "1.0.3" +"@radix-ui/react-dismissable-layer@1.1.19": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz#ef64a08943bdf04e00996f55472456353014fa68" + integrity sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-effect-event" "0.0.5" + +"@radix-ui/react-dropdown-menu@2.1.24": + version "2.1.24" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.24.tgz#3ed6d50cdacb1e68a5230c13510b6a87131b577b" + integrity sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-menu" "2.1.24" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-focus-guards@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad" @@ -3088,6 +3392,11 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-focus-guards@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz#853985fb77fb7f6f65ab2e4750d1cfde9c702e36" + integrity sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ== + "@radix-ui/react-focus-scope@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.3.tgz#9c2e8d4ed1189a1d419ee61edd5c1828726472f9" @@ -3098,6 +3407,42 @@ "@radix-ui/react-primitive" "1.0.3" "@radix-ui/react-use-callback-ref" "1.0.1" +"@radix-ui/react-focus-scope@1.1.16": + version "1.1.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz#1221498b222efaae678a25ae4b81025c5feda195" + integrity sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ== + dependencies: + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + +"@radix-ui/react-form@0.1.16": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-form/-/react-form-0.1.16.tgz#58450bddb18e2ce61f1f62756bbcb2304524fd5b" + integrity sha512-Q4TLEn2A7TAypxwmd6R9EwrlXDvkfYSDMrq9/887AXAGh+G1rH+kYJKSTv+Si9Y0JPKTwKYv6PviAJosysNimA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-label" "2.1.15" + "@radix-ui/react-primitive" "2.1.10" + +"@radix-ui/react-hover-card@1.1.23": + version "1.1.23" + resolved "https://registry.yarnpkg.com/@radix-ui/react-hover-card/-/react-hover-card-1.1.23.tgz#9543671321afb3e822d1bfab8cc1016cc4d95e9e" + integrity sha512-H8qONfZd3ltrU3+jHCIgITbWo6e1iTKvP9DHdrvYbX48ooRM5FjEDTn16AMwdfuOGkWdZEhpl3PLL/Wk/AnHDQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-id@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0" @@ -3113,6 +3458,133 @@ dependencies: "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-id@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.4.tgz#e642714bdaf551c1bfacbe51508ed843a3a27980" + integrity sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-label@2.1.15": + version "2.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-2.1.15.tgz#d6df361e853d8de9e3a512f6772b646fdb8d34e7" + integrity sha512-o/rdYEwZTTo5tjknnPeyQFU45kUC4i/XyeDPP+HGyi6XqpOP6Zf5Ya5vh/Yfe9Id5JiuWnnAx2XqIeD3UYZt0g== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + +"@radix-ui/react-menu@2.1.24": + version "2.1.24" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.24.tgz#cd875e66fb0eb5ec5381132933e0d790d043edcc" + integrity sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-callback-ref" "1.1.4" + aria-hidden "^1.2.4" + react-remove-scroll "^2.7.2" + +"@radix-ui/react-menubar@1.1.24": + version "1.1.24" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menubar/-/react-menubar-1.1.24.tgz#9cd0181cb03bbe971417c76339ed54dbd1d6bbf7" + integrity sha512-eeVs0vf7cuqXaM0qLQCPcufImiJNVBXdJDLu7ZGYl2732UH23Qat/foNGrr6vYV3/DdTsBqASoggUFgH14OcZA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-menu" "2.1.24" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-use-controllable-state" "1.2.6" + +"@radix-ui/react-navigation-menu@1.2.22": + version "1.2.22" + resolved "https://registry.yarnpkg.com/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.22.tgz#e6db06a6bb188233c7db3616e7f76328705570dd" + integrity sha512-ou7iLEJ+yrhQndkkA4U21XIdS/CS45F4iXIkTZcb6/Ne9EMsOuDudVmCwmDnfFZZ+y1FZqXRNSIgBy+YMvZVZg== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-previous" "1.1.4" + "@radix-ui/react-visually-hidden" "1.2.11" + +"@radix-ui/react-one-time-password-field@0.1.16": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.16.tgz#8cd79d69c626ca13e3c2c741f36d092146919f99" + integrity sha512-Tj9P6ntAJEw52oq/F0AGknXR4XncxEt7XU47O3xJQOiWfLzEy3d9gtgKfvjSzGxzHkfL+VzvxGu2KTFsloJqXw== + dependencies: + "@radix-ui/number" "1.1.3" + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-effect-event" "0.0.5" + "@radix-ui/react-use-is-hydrated" "0.1.3" + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-password-toggle-field@0.1.11": + version "0.1.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.11.tgz#53e9cb2a2565356321858c85e2988ba7847a939f" + integrity sha512-4gvFnmDXu3dgj21CqsufzIameRvlRd4SBqaWhcrlrNhRo0Y5i/49AmRJYe1fdAM3G2VNBbmin4b0D6cdQocwgw== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-effect-event" "0.0.5" + "@radix-ui/react-use-is-hydrated" "0.1.3" + +"@radix-ui/react-popover@1.1.23": + version "1.1.23" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.23.tgz#0d3bfb292d4ac14625022c581029d0e596a52308" + integrity sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-controllable-state" "1.2.6" + aria-hidden "^1.2.4" + react-remove-scroll "^2.7.2" + "@radix-ui/react-popper@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.2.tgz#4c0b96fcd188dc1f334e02dba2d538973ad842e9" @@ -3130,6 +3602,22 @@ "@radix-ui/react-use-size" "1.0.1" "@radix-ui/rect" "1.0.1" +"@radix-ui/react-popper@1.3.7": + version "1.3.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.3.7.tgz#a46002dec97f989e6279453727b1b0ba63691677" + integrity sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg== + dependencies: + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-rect" "1.1.4" + "@radix-ui/react-use-size" "1.1.4" + "@radix-ui/rect" "1.1.3" + "@radix-ui/react-portal@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.3.tgz#ffb961244c8ed1b46f039e6c215a6c4d9989bda1" @@ -3138,6 +3626,21 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.3" +"@radix-ui/react-portal@1.1.17": + version "1.1.17" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.17.tgz#f3b60bb5d78f12143e17553c45ed0506b026ec18" + integrity sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-presence@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.10.tgz#49041cb9c41c3e8d1791d6b96a1d3bcd8429a151" + integrity sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-primitive@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" @@ -3146,6 +3649,13 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-slot" "1.0.2" +"@radix-ui/react-primitive@2.1.10", "@radix-ui/react-primitive@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz#292b7476499d17227f337c8d1c59f270c683842a" + integrity sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg== + dependencies: + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-primitive@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz#db9b8bcff49e01be510ad79893fb0e4cda50f1bc" @@ -3153,6 +3663,29 @@ dependencies: "@radix-ui/react-slot" "1.2.3" +"@radix-ui/react-progress@1.1.16": + version "1.1.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-progress/-/react-progress-1.1.16.tgz#250b03532573ba603f074b7702388a9427a5bcc4" + integrity sha512-5XnomAsoZZCY+KNTxbIghpGqPruZvKFNlvcAljVAOdDRDsH4/OZQxhtwo5wdtoDM5R6MhJBb2sPnDuRFep3lzg== + dependencies: + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-primitive" "2.1.10" + +"@radix-ui/react-radio-group@1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-radio-group/-/react-radio-group-1.4.7.tgz#915d083547d26d763884b7683be469c6402aed96" + integrity sha512-cgYFEkntCxppHZgtSZ+7vh0wbZQ+IC7PPMw8DSnRG27B6kDd32/Zw0OJt7dGDigCoprMuWHjg2PvUn3PYvPFoQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-size" "1.1.4" + "@radix-ui/react-roving-focus@1.1.11": version "1.1.11" resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz#ef54384b7361afc6480dcf9907ef2fedb5080fd9" @@ -3168,6 +3701,66 @@ "@radix-ui/react-use-callback-ref" "1.1.1" "@radix-ui/react-use-controllable-state" "1.2.2" +"@radix-ui/react-roving-focus@1.1.19": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.19.tgz#2abc0676448f4ebae8c43a61f9531aebe0f5c823" + integrity sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-is-hydrated" "0.1.3" + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-scroll-area@1.2.18": + version "1.2.18" + resolved "https://registry.yarnpkg.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.18.tgz#93c16378e812ad5fe9ba0abd635b51c840021162" + integrity sha512-Zn5Cd171wxsO3Dfg8HaW6RifTb9CYTKQJHs/G4+LN1GfmJpaQMZQyQxMprVPHpaz7QY4l9BxK2JwQuzHsXC8nA== + dependencies: + "@radix-ui/number" "1.1.3" + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-select@2.3.7": + version "2.3.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.3.7.tgz#fc83ddd866decff8ca99e63f093c6e387ad54790" + integrity sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg== + dependencies: + "@radix-ui/number" "1.1.3" + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-previous" "1.1.4" + "@radix-ui/react-visually-hidden" "1.2.11" + aria-hidden "^1.2.4" + react-remove-scroll "^2.7.2" + "@radix-ui/react-select@^1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-1.2.2.tgz#caa981fa0d672cf3c1b2a5240135524e69b32181" @@ -3196,6 +3789,13 @@ aria-hidden "^1.1.1" react-remove-scroll "2.5.5" +"@radix-ui/react-separator@1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.15.tgz#0b59a55ce42f881bda6da45a1cc8069214a8606c" + integrity sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-separator@1.1.7": version "1.1.7" resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.7.tgz#a18bd7fd07c10fda1bba14f2a3032e7b1a2b3470" @@ -3203,6 +3803,23 @@ dependencies: "@radix-ui/react-primitive" "2.1.3" +"@radix-ui/react-slider@1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-1.4.7.tgz#937c44ba404404a2fbf572863a3b4c44635d50e8" + integrity sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg== + dependencies: + "@radix-ui/number" "1.1.3" + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-previous" "1.1.4" + "@radix-ui/react-use-size" "1.1.4" + "@radix-ui/react-slot@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" @@ -3218,6 +3835,57 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.2" +"@radix-ui/react-slot@1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.3.3.tgz#ccc8c8936fff12f7e324d6917fe5167357097676" + integrity sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q== + dependencies: + "@radix-ui/react-compose-refs" "1.1.5" + +"@radix-ui/react-switch@1.3.7": + version "1.3.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-switch/-/react-switch-1.3.7.tgz#54dc0d331145418c2e3ac6545c166b89cb1e186e" + integrity sha512-48tB/4dn2UVLBCYhTu9AuR63IHl73l/qLbLgxd86noTUor4/K4LFDAcYjK+isP5313qxaFpjPVogE7+Y0/V3Kw== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-size" "1.1.4" + +"@radix-ui/react-tabs@1.1.21": + version "1.1.21" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.1.21.tgz#db7eb9b33f25d645a6a21028e9e0047d457c49a0" + integrity sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-use-controllable-state" "1.2.6" + +"@radix-ui/react-toast@1.2.23": + version "1.2.23" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-1.2.23.tgz#b64e2e2b735b4f2188fd79f446e0e2cbc624d088" + integrity sha512-ofhyAsYaocRGOs/n0XWdUOSVzEAG6BfrMVM8z0c0kLEWY38w/0WuMFPTJP/HVaZPYkMvHZoKIIhNcjbTCBILPg== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-visually-hidden" "1.2.11" + "@radix-ui/react-toggle-group@1.1.11": version "1.1.11" resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz#e513d6ffdb07509b400ab5b26f2523747c0d51c1" @@ -3231,6 +3899,19 @@ "@radix-ui/react-toggle" "1.1.10" "@radix-ui/react-use-controllable-state" "1.2.2" +"@radix-ui/react-toggle-group@1.1.19": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.19.tgz#cefc32db4e117e5a15812bb944676a4d14d9e59b" + integrity sha512-OtnwuSVjd1Ofi+AdnvhsjQdyuhCDwYs1w9RyB5BN/OavXOVQo42SYqQjwUnbPnaiPFBpQ9aX70dWeee+v2oBLA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-toggle" "1.1.18" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-toggle@1.1.10": version "1.1.10" resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz#b04ba0f9609599df666fce5b2f38109a197f08cf" @@ -3240,6 +3921,28 @@ "@radix-ui/react-primitive" "2.1.3" "@radix-ui/react-use-controllable-state" "1.2.2" +"@radix-ui/react-toggle@1.1.18": + version "1.1.18" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.1.18.tgz#3b464b235e76193142d9ea276611a9c8ef3babc7" + integrity sha512-7lonPlKfSacd20GlOBx2ltuVKz9oqWYZz+oMQyOltw6t1y2nyftj2ZmwwUHYn49kqfDWcp8dNZm5NgV+5Z+mug== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + +"@radix-ui/react-toolbar@1.1.19": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toolbar/-/react-toolbar-1.1.19.tgz#91add5b6fa994cb79b0a857d57ab08bfa472f079" + integrity sha512-Ph0IvtYw4VB12ZnZg+YtrGs8yJQsnizwo/zu0R4Y/nWugtJzA7Pg1eWeuDR9+LSqn+xjamss+UOSOJJJ4gx8jw== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-separator" "1.1.15" + "@radix-ui/react-toggle-group" "1.1.19" + "@radix-ui/react-toolbar@^1.0.4": version "1.1.11" resolved "https://registry.yarnpkg.com/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz#2a71f1d91535788f88145d542159e2faaa561db7" @@ -3253,6 +3956,25 @@ "@radix-ui/react-separator" "1.1.7" "@radix-ui/react-toggle-group" "1.1.11" +"@radix-ui/react-tooltip@1.2.16": + version "1.2.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.2.16.tgz#b38fc8475b4d5619b0f50fa057390b278a5d4e69" + integrity sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-visually-hidden" "1.2.11" + "@radix-ui/react-use-callback-ref@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" @@ -3265,6 +3987,11 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz#62a4dba8b3255fdc5cc7787faeac1c6e4cc58d40" integrity sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg== +"@radix-ui/react-use-callback-ref@1.1.4", "@radix-ui/react-use-callback-ref@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz#1e55d37148e60a3f47de4bc7ea7cff6fa3f425ae" + integrity sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ== + "@radix-ui/react-use-controllable-state@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286" @@ -3281,6 +4008,15 @@ "@radix-ui/react-use-effect-event" "0.0.2" "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-use-controllable-state@1.2.6", "@radix-ui/react-use-controllable-state@^1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz#0f109eff004c3c1ff5f9709570f45dee9955513e" + integrity sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-use-effect-event" "0.0.5" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-effect-event@0.0.2": version "0.0.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz#090cf30d00a4c7632a15548512e9152217593907" @@ -3288,6 +4024,13 @@ dependencies: "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-use-effect-event@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz#7732a4ae6bc032c7f654e658203df92d3520f8d1" + integrity sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-escape-keydown@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755" @@ -3296,6 +4039,18 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-callback-ref" "1.0.1" +"@radix-ui/react-use-escape-keydown@1.1.5", "@radix-ui/react-use-escape-keydown@^1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.5.tgz#c024607d925f9a86305056eb245b09ef3eff6d2a" + integrity sha512-ge3ipobwSXTj4JyVtswQ7qZj0ZHdtbGuOno/LrgAAeSxtsJ6Vs4Gz5IkPH2bmqpjcLUFoqGhA/mueuIf63UXlA== + dependencies: + "@radix-ui/react-use-callback-ref" "1.1.4" + +"@radix-ui/react-use-is-hydrated@0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.3.tgz#f0ffa47394726046ba6c6d0b7c97239f48c8df45" + integrity sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw== + "@radix-ui/react-use-layout-effect@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399" @@ -3308,6 +4063,11 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz#0c4230a9eed49d4589c967e2d9c0d9d60a23971e" integrity sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ== +"@radix-ui/react-use-layout-effect@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz#51a0bbc342315070983383b3f8f00061083782a8" + integrity sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw== + "@radix-ui/react-use-previous@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66" @@ -3315,6 +4075,11 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-use-previous@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.4.tgz#4a2789c168d85a78e51f812c3e9727ef01d302da" + integrity sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg== + "@radix-ui/react-use-rect@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2" @@ -3323,6 +4088,13 @@ "@babel/runtime" "^7.13.10" "@radix-ui/rect" "1.0.1" +"@radix-ui/react-use-rect@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz#9d68dd1d149a0af4f228c5c9ae4646d3ceaa0e2a" + integrity sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ== + dependencies: + "@radix-ui/rect" "1.1.3" + "@radix-ui/react-use-size@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz#1c5f5fea940a7d7ade77694bb98116fb49f870b2" @@ -3331,6 +4103,13 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-layout-effect" "1.0.1" +"@radix-ui/react-use-size@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.4.tgz#2d6d0a97a5cd11a76f4f09984239d9e26c59ce4e" + integrity sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-visually-hidden@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz#51aed9dd0fe5abcad7dee2a234ad36106a6984ac" @@ -3339,6 +4118,13 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.3" +"@radix-ui/react-visually-hidden@1.2.11": + version "1.2.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.11.tgz#3e02aebf825d74042d1b863a20ccc67316b78e7b" + integrity sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/rect@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.1.tgz#bf8e7d947671996da2e30f4904ece343bc4a883f" @@ -3346,6 +4132,11 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/rect@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.3.tgz#5a58fbae3deefb7f8cfe6ea314287d699eb694a9" + integrity sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw== + "@rollup/plugin-babel@^5.2.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" @@ -4771,7 +5562,14 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^1.0.8": +"@types/estree-jsx@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" + integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== + dependencies: + "@types/estree" "*" + +"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.8": version "1.0.9" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24" integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg== @@ -5552,6 +6350,11 @@ resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz#72da0da48d72b1e87831b9c0308931d3f4669027" integrity sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA== +"@vercel/oidc@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@vercel/oidc/-/oidc-3.2.0.tgz#5782a4d4904443f015808705b5537cf9c3b68528" + integrity sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug== + "@wdio/junit-reporter@^7.40.0": version "7.40.0" resolved "https://registry.yarnpkg.com/@wdio/junit-reporter/-/junit-reporter-7.40.0.tgz#1719f69a7be3a383bbcd90d95ee3e98861bbec77" @@ -5727,6 +6530,11 @@ resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== +"@workflow/serde@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@workflow/serde/-/serde-4.1.0.tgz#82dbbaf2370f7b8ae46d9a9a4ab0917258f8db62" + integrity sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ== + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -5856,6 +6664,15 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ai@7.0.79, ai@^7.0.66: + version "7.0.79" + resolved "https://registry.yarnpkg.com/ai/-/ai-7.0.79.tgz#e98500047372dfe1013a576f84c1379b8551e16e" + integrity sha512-zZkSUq6MgmXjwIfML2wkPFeQ5Azk8kGEWkciAtE0NgnFy3slj4ljsw5LvigsCbYXxTSVr+6iCHBTPZafpx1P0w== + dependencies: + "@ai-sdk/gateway" "4.0.64" + "@ai-sdk/provider" "4.0.8" + "@ai-sdk/provider-utils" "5.0.30" + ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" @@ -6031,7 +6848,7 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-hidden@^1.1.1: +aria-hidden@^1.1.1, aria-hidden@^1.2.4: version "1.2.6" resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.6.tgz#73051c9b088114c795b1ea414e9c0fff874ffc1a" integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA== @@ -6176,6 +6993,22 @@ assert@^2.1.0: object.assign "^4.1.4" util "^0.12.5" +assistant-cloud@*, assistant-cloud@^0.1.41: + version "0.1.41" + resolved "https://registry.yarnpkg.com/assistant-cloud/-/assistant-cloud-0.1.41.tgz#b2dc79611ce1d7be119ff531a62cd144d496ae64" + integrity sha512-lrH9USOoNaAWAAbujeHa/PEiWoqNQHjIPIAeeA3y3GUXOdlmTjIyR/7GbEZBKbHhm1Lyt7aAYKvdxHFkhuEbJw== + dependencies: + assistant-stream "^0.3.38" + +assistant-stream@^0.3.38, assistant-stream@^0.3.39: + version "0.3.39" + resolved "https://registry.yarnpkg.com/assistant-stream/-/assistant-stream-0.3.39.tgz#521a9b8b296cc441e1dfccb0858ea18722269eb3" + integrity sha512-Ad28saCwQxqaB69w4WNaS3uW5OW5BgTYnzTfbgFnz1CPXZjcWFsMrHhcJUpR4+lfYPTNal0oHEb47VUZH4Zz1g== + dependencies: + "@standard-schema/spec" "^1.1.0" + nanoid "^6.0.1" + secure-json-parse "^4.1.0" + ast-types-flow@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" @@ -6953,6 +7786,11 @@ character-entities@^2.0.0: resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== +character-reference-invalid@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" + integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== + check-more-types@2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" @@ -8010,7 +8848,7 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -dequal@^2.0.0, dequal@^2.0.2: +dequal@^2.0.0, dequal@^2.0.2, dequal@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== @@ -8068,7 +8906,7 @@ detect-port@^1.3.0: address "^1.0.1" debug "4" -devlop@^1.0.0: +devlop@^1.0.0, devlop@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== @@ -9107,6 +9945,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-util-is-identifier-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd" + integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== + estree-walker@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" @@ -9155,6 +9998,11 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +eventsource-parser@^3.0.8: + version "3.1.1" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.1.1.tgz#b96cbb7dace4f3774f58a9e3b1ae9a4a524872e2" + integrity sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ== + execa@5.1.1, execa@^5.0.0, execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -10260,6 +11108,27 @@ hast-util-to-html@^9.0.0: stringify-entities "^4.0.0" zwitch "^2.0.4" +hast-util-to-jsx-runtime@^2.0.0: + version "2.3.6" + resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz#ff31897aae59f62232e21594eac7ef6b63333e98" + integrity sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg== + dependencies: + "@types/estree" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + comma-separated-tokens "^2.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + hast-util-whitespace "^3.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + style-to-js "^1.0.0" + unist-util-position "^5.0.0" + vfile-message "^4.0.0" + hast-util-to-parse5@^8.0.0: version "8.0.1" resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz#95aa391cc0514b4951418d01c883d1038af42f5d" @@ -10383,6 +11252,11 @@ html-tags@^3.1.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== +html-url-attributes@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.1.tgz#83b052cd5e437071b756cd74ae70f708870c2d87" + integrity sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ== + html-void-elements@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-3.0.0.tgz#fc9dbd84af9e747249034d4d62602def6517f1d7" @@ -10662,6 +11536,11 @@ inline-style-parser@0.1.1: resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== +inline-style-parser@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.7.tgz#b1fc68bfc0313b8685745e4464e37f9376b9c909" + integrity sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA== + internal-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" @@ -10698,6 +11577,19 @@ is-absolute-url@^3.0.0: resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== +is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + +is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.2.0.tgz#ad58c6aecf563b78ef2bf04df540da8f5d7d8e1b" @@ -10801,6 +11693,11 @@ is-date-object@^1.0.5, is-date-object@^1.1.0: call-bound "^1.0.2" has-tostringtag "^1.0.2" +is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + is-deflate@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14" @@ -10861,6 +11758,11 @@ is-gzip@^1.0.0: resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83" integrity sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ== +is-hexadecimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" + integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== + is-inside-container@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" @@ -12245,6 +13147,11 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -12718,6 +13625,16 @@ mdast-util-find-and-replace@^2.0.0: unist-util-is "^5.0.0" unist-util-visit-parents "^5.0.0" +mdast-util-find-and-replace@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz#70a3174c894e14df722abf43bc250cbae44b11df" + integrity sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg== + dependencies: + "@types/mdast" "^4.0.0" + escape-string-regexp "^5.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + mdast-util-from-markdown@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0" @@ -12773,6 +13690,17 @@ mdast-util-gfm-autolink-literal@^1.0.0: mdast-util-find-and-replace "^2.0.0" micromark-util-character "^1.0.0" +mdast-util-gfm-autolink-literal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz#abd557630337bd30a6d5a4bd8252e1c2dc0875d5" + integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ== + dependencies: + "@types/mdast" "^4.0.0" + ccount "^2.0.0" + devlop "^1.0.0" + mdast-util-find-and-replace "^3.0.0" + micromark-util-character "^2.0.0" + mdast-util-gfm-footnote@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz#ce5e49b639c44de68d5bf5399877a14d5020424e" @@ -12782,6 +13710,17 @@ mdast-util-gfm-footnote@^1.0.0: mdast-util-to-markdown "^1.3.0" micromark-util-normalize-identifier "^1.0.0" +mdast-util-gfm-footnote@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz#7778e9d9ca3df7238cc2bd3fa2b1bf6a65b19403" + integrity sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + mdast-util-gfm-strikethrough@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz#5470eb105b483f7746b8805b9b989342085795b7" @@ -12790,6 +13729,15 @@ mdast-util-gfm-strikethrough@^1.0.0: "@types/mdast" "^3.0.0" mdast-util-to-markdown "^1.3.0" +mdast-util-gfm-strikethrough@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz#d44ef9e8ed283ac8c1165ab0d0dfd058c2764c16" + integrity sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + mdast-util-gfm-table@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz#3552153a146379f0f9c4c1101b071d70bbed1a46" @@ -12800,6 +13748,17 @@ mdast-util-gfm-table@^1.0.0: mdast-util-from-markdown "^1.0.0" mdast-util-to-markdown "^1.3.0" +mdast-util-gfm-table@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz#7a435fb6223a72b0862b33afbd712b6dae878d38" + integrity sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + markdown-table "^3.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + mdast-util-gfm-task-list-item@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz#b280fcf3b7be6fd0cc012bbe67a59831eb34097b" @@ -12808,6 +13767,16 @@ mdast-util-gfm-task-list-item@^1.0.0: "@types/mdast" "^3.0.0" mdast-util-to-markdown "^1.3.0" +mdast-util-gfm-task-list-item@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz#e68095d2f8a4303ef24094ab642e1047b991a936" + integrity sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + mdast-util-gfm@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz#e92f4d8717d74bdba6de57ed21cc8b9552e2d0b6" @@ -12821,6 +13790,61 @@ mdast-util-gfm@^2.0.0: mdast-util-gfm-task-list-item "^1.0.0" mdast-util-to-markdown "^1.0.0" +mdast-util-gfm@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz#2cdf63b92c2a331406b0fb0db4c077c1b0331751" + integrity sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ== + dependencies: + mdast-util-from-markdown "^2.0.0" + mdast-util-gfm-autolink-literal "^2.0.0" + mdast-util-gfm-footnote "^2.0.0" + mdast-util-gfm-strikethrough "^2.0.0" + mdast-util-gfm-table "^2.0.0" + mdast-util-gfm-task-list-item "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdx-expression@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz#43f0abac9adc756e2086f63822a38c8d3c3a5096" + integrity sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdx-jsx@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz#fd04c67a2a7499efb905a8a5c578dddc9fdada0d" + integrity sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + ccount "^2.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" + +mdast-util-mdxjs-esm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz#019cfbe757ad62dd557db35a695e7314bcc9fa97" + integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + mdast-util-newline-to-break@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mdast-util-newline-to-break/-/mdast-util-newline-to-break-1.0.0.tgz#a42699874a9240dc89bfcf256d3ff3036856abba" @@ -12837,6 +13861,14 @@ mdast-util-phrasing@^3.0.0: "@types/mdast" "^3.0.0" unist-util-is "^5.0.0" +mdast-util-phrasing@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz#7cc0a8dec30eaf04b7b1a9661a92adb3382aa6e3" + integrity sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== + dependencies: + "@types/mdast" "^4.0.0" + unist-util-is "^6.0.0" + mdast-util-to-hast@^12.1.0: version "12.3.0" resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49" @@ -12880,6 +13912,21 @@ mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: unist-util-visit "^4.0.0" zwitch "^2.0.0" +mdast-util-to-markdown@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz#f910ffe60897f04bb4b7e7ee434486f76288361b" + integrity sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-decode-string "^2.0.0" + unist-util-visit "^5.0.0" + zwitch "^2.0.0" + mdast-util-to-string@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527" @@ -13037,6 +14084,16 @@ micromark-extension-gfm-autolink-literal@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-extension-gfm-autolink-literal@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935" + integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-gfm-footnote@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz#05e13034d68f95ca53c99679040bc88a6f92fe2e" @@ -13051,6 +14108,20 @@ micromark-extension-gfm-footnote@^1.0.0: micromark-util-types "^1.0.0" uvu "^0.5.0" +micromark-extension-gfm-footnote@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750" + integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw== + dependencies: + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-gfm-strikethrough@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz#c8212c9a616fa3bf47cb5c711da77f4fdc2f80af" @@ -13063,6 +14134,18 @@ micromark-extension-gfm-strikethrough@^1.0.0: micromark-util-types "^1.0.0" uvu "^0.5.0" +micromark-extension-gfm-strikethrough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923" + integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-gfm-table@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz#dcb46074b0c6254c3fc9cc1f6f5002c162968008" @@ -13074,6 +14157,17 @@ micromark-extension-gfm-table@^1.0.0: micromark-util-types "^1.0.0" uvu "^0.5.0" +micromark-extension-gfm-table@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz#fac70bcbf51fe65f5f44033118d39be8a9b5940b" + integrity sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg== + dependencies: + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-gfm-tagfilter@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz#aa7c4dd92dabbcb80f313ebaaa8eb3dac05f13a7" @@ -13081,6 +14175,13 @@ micromark-extension-gfm-tagfilter@^1.0.0: dependencies: micromark-util-types "^1.0.0" +micromark-extension-gfm-tagfilter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz#f26d8a7807b5985fba13cf61465b58ca5ff7dc57" + integrity sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg== + dependencies: + micromark-util-types "^2.0.0" + micromark-extension-gfm-task-list-item@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz#b52ce498dc4c69b6a9975abafc18f275b9dde9f4" @@ -13092,6 +14193,17 @@ micromark-extension-gfm-task-list-item@^1.0.0: micromark-util-types "^1.0.0" uvu "^0.5.0" +micromark-extension-gfm-task-list-item@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c" + integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw== + dependencies: + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-gfm@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz#e517e8579949a5024a493e49204e884aa74f5acf" @@ -13106,6 +14218,20 @@ micromark-extension-gfm@^2.0.0: micromark-util-combine-extensions "^1.0.0" micromark-util-types "^1.0.0" +micromark-extension-gfm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz#3e13376ab95dd7a5cfd0e29560dfe999657b3c5b" + integrity sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w== + dependencies: + micromark-extension-gfm-autolink-literal "^2.0.0" + micromark-extension-gfm-footnote "^2.0.0" + micromark-extension-gfm-strikethrough "^2.0.0" + micromark-extension-gfm-table "^2.0.0" + micromark-extension-gfm-tagfilter "^2.0.0" + micromark-extension-gfm-task-list-item "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-destination@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz#eb815957d83e6d44479b3df640f010edad667b9f" @@ -13670,6 +14796,11 @@ nanoid@^3.3.16: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.17.tgz#f1c3aa253c52547956a52c50bff754316f61037a" integrity sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g== +nanoid@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-6.0.1.tgz#a04a2304f05b620c600ae8464d94c325ceeebd35" + integrity sha512-3wVS3i51pE2pi1k5FFL/95BGfVS0kSsvDVuGXHOtxox/TywUmtgq+3qiTOTbs9J7KfHaXPiN171k/A6dBnaXFw== + napi-postinstall@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.4.tgz#7af256d6588b5f8e952b9190965d6b019653bbb9" @@ -14165,6 +15296,19 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-entities@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.2.tgz#61d46f5ed28e4ee62e9ddc43d6b010188443f159" + integrity sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw== + dependencies: + "@types/unist" "^2.0.0" + character-entities-legacy "^3.0.0" + character-reference-invalid "^2.0.0" + decode-named-character-reference "^1.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + is-hexadecimal "^2.0.0" + parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -14352,6 +15496,11 @@ pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.6: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== +pkce-challenge@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz#3b4446865b17b1745e9ace2016a31f48ddf6230d" + integrity sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ== + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -15280,6 +16429,67 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +radix-ui@^1.6.7: + version "1.6.7" + resolved "https://registry.yarnpkg.com/radix-ui/-/radix-ui-1.6.7.tgz#0a40f1b1a70a7aee9c4faa691d03361f53f881f0" + integrity sha512-QBdhh1arIEUvPC0dQ5+nwWAxt7+N+oP/9jPwjJkGFoSk/sqxg32gJtSXGtFh8frAIcS6oC9cx2Q+7KYCQLOAeA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-accessible-icon" "1.1.15" + "@radix-ui/react-accordion" "1.2.20" + "@radix-ui/react-alert-dialog" "1.1.23" + "@radix-ui/react-arrow" "1.1.15" + "@radix-ui/react-aspect-ratio" "1.1.15" + "@radix-ui/react-avatar" "1.2.6" + "@radix-ui/react-checkbox" "1.3.11" + "@radix-ui/react-collapsible" "1.1.20" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-context-menu" "2.3.7" + "@radix-ui/react-dialog" "1.1.23" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-dropdown-menu" "2.1.24" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-form" "0.1.16" + "@radix-ui/react-hover-card" "1.1.23" + "@radix-ui/react-label" "2.1.15" + "@radix-ui/react-menu" "2.1.24" + "@radix-ui/react-menubar" "1.1.24" + "@radix-ui/react-navigation-menu" "1.2.22" + "@radix-ui/react-one-time-password-field" "0.1.16" + "@radix-ui/react-password-toggle-field" "0.1.11" + "@radix-ui/react-popover" "1.1.23" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-progress" "1.1.16" + "@radix-ui/react-radio-group" "1.4.7" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-scroll-area" "1.2.18" + "@radix-ui/react-select" "2.3.7" + "@radix-ui/react-separator" "1.1.15" + "@radix-ui/react-slider" "1.4.7" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-switch" "1.3.7" + "@radix-ui/react-tabs" "1.1.21" + "@radix-ui/react-toast" "1.2.23" + "@radix-ui/react-toggle" "1.1.18" + "@radix-ui/react-toggle-group" "1.1.19" + "@radix-ui/react-toolbar" "1.1.19" + "@radix-ui/react-tooltip" "1.2.16" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-effect-event" "0.0.5" + "@radix-ui/react-use-escape-keydown" "1.1.5" + "@radix-ui/react-use-is-hydrated" "0.1.3" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-size" "1.1.4" + "@radix-ui/react-visually-hidden" "1.2.11" + raf-schd@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" @@ -15592,6 +16802,23 @@ react-markdown@8.0.7: unist-util-visit "^4.0.0" vfile "^5.0.0" +react-markdown@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-10.1.0.tgz#e22bc20faddbc07605c15284255653c0f3bad5ca" + integrity sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + hast-util-to-jsx-runtime "^2.0.0" + html-url-attributes "^3.0.0" + mdast-util-to-hast "^13.0.0" + remark-parse "^11.0.0" + remark-rehype "^11.0.0" + unified "^11.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + react-onclickoutside@^6.13.0: version "6.13.2" resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.2.tgz#caa6df2c0cfe017506548fa810303fb85d13fb7c" @@ -15653,7 +16880,7 @@ react-refresh@^0.14.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== -react-remove-scroll-bar@^2.3.3: +react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.7: version "2.3.8" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223" integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q== @@ -15672,6 +16899,17 @@ react-remove-scroll@2.5.5: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" +react-remove-scroll@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz#6442da56791117661978ae99cd29be9026fecca0" + integrity sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q== + dependencies: + react-remove-scroll-bar "^2.3.7" + react-style-singleton "^2.2.3" + tslib "^2.1.0" + use-callback-ref "^1.3.3" + use-sidecar "^1.1.3" + react-responsive-modal@^6.4.2: version "6.4.2" resolved "https://registry.yarnpkg.com/react-responsive-modal/-/react-responsive-modal-6.4.2.tgz#666b5c35b232cec617981006c9fe59414531a5a0" @@ -15786,7 +17024,7 @@ react-spinners@^0.17.0: resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.17.0.tgz#d518913e2192afaae76c5b781929ea3bd7b1910e" integrity sha512-L/8HTylaBmIWwQzIjMq+0vyaRXuoAevzWoD35wKpNTxxtYXWZp+xtgkfD7Y4WItuX0YvdxMPU79+7VhhmbmuTQ== -react-style-singleton@^2.2.1, react-style-singleton@^2.2.2: +react-style-singleton@^2.2.1, react-style-singleton@^2.2.2, react-style-singleton@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388" integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ== @@ -15801,6 +17039,15 @@ react-swipeable@^5.5.1: dependencies: prop-types "^15.6.2" +react-textarea-autosize@^8.5.9: + version "8.5.9" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.9.tgz#ab8627b09aa04d8a2f45d5b5cd94c84d1d4a8893" + integrity sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A== + dependencies: + "@babel/runtime" "^7.20.13" + use-composed-ref "^1.3.0" + use-latest "^1.2.1" + react-toastify@^9.1.3: version "9.1.3" resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-9.1.3.tgz#1e798d260d606f50e0fab5ee31daaae1d628c5ff" @@ -16165,6 +17412,18 @@ remark-frontmatter@^4.0.1: micromark-extension-frontmatter "^1.0.0" unified "^10.0.0" +"remark-gfm-v4@npm:remark-gfm@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-4.0.1.tgz#33227b2a74397670d357bf05c098eaf8513f0d6b" + integrity sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-gfm "^3.0.0" + micromark-extension-gfm "^3.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" + remark-gfm@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" @@ -16204,6 +17463,17 @@ remark-rehype@^10.0.0: mdast-util-to-hast "^12.1.0" unified "^10.0.0" +remark-rehype@^11.0.0: + version "11.1.2" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.2.tgz#2addaadda80ca9bd9aa0da763e74d16327683b37" + integrity sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-hast "^13.0.0" + unified "^11.0.0" + vfile "^6.0.0" + remark-slug@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-6.1.0.tgz#0503268d5f0c4ecb1f33315c00465ccdd97923ce" @@ -16213,6 +17483,15 @@ remark-slug@^6.0.0: mdast-util-to-string "^1.0.0" unist-util-visit "^2.0.0" +remark-stringify@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-11.0.0.tgz#4c5b01dd711c269df1aaae11743eb7e2e7636fd3" + integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-to-markdown "^2.0.0" + unified "^11.0.0" + remove@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/remove/-/remove-0.1.5.tgz#095ffd827d65c9f41ad97d33e416a75811079955" @@ -16449,6 +17728,11 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-content-frame@^0.0.27: + version "0.0.27" + resolved "https://registry.yarnpkg.com/safe-content-frame/-/safe-content-frame-0.0.27.tgz#544d5b5f737893893d5db9d7ef4e27096fa34f9d" + integrity sha512-IFUSMjElIp8q46wUU5HViHNEqoDWRlCzqqThQmhOLimuXPe/QC6Jr/AQ+BKxSYziQdNXUpapBq4Ir/t6dS0Ldg== + safe-push-apply@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" @@ -16578,6 +17862,11 @@ schema-utils@^4.0.0, schema-utils@^4.2.0, schema-utils@^4.3.0, schema-utils@^4.3 ajv-formats "^2.1.1" ajv-keywords "^5.1.0" +secure-json-parse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-4.1.0.tgz#4f1ab41c67a13497ea1b9131bb4183a22865477c" + integrity sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA== + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -17330,6 +18619,20 @@ style-mod@^4.0.0, style-mod@^4.1.0: resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.3.tgz#6e9012255bb799bdac37e288f7671b5d71bf9f73" integrity sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ== +style-to-js@^1.0.0: + version "1.1.21" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.21.tgz#2908941187f857e79e28e9cd78008b9a0b3e0e8d" + integrity sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ== + dependencies: + style-to-object "1.0.14" + +style-to-object@1.0.14: + version "1.0.14" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.14.tgz#1d22f0e7266bb8c6d8cae5caf4ec4f005e08f611" + integrity sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw== + dependencies: + inline-style-parser "0.2.7" + style-to-object@^0.4.0: version "0.4.4" resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.4.tgz#266e3dfd56391a7eefb7770423612d043c3f33ec" @@ -17498,6 +18801,14 @@ swr@^1.3.0: resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8" integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw== +swr@^2.4.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/swr/-/swr-2.5.1.tgz#3d1801fafe06d13b149bc52c62323dcd43ca570c" + integrity sha512-BRw55e8r0B7SpDN20CAzoQAHl7y1yP7/Zt7oqUjMv0vSt2u2Xnkm88Ws+VypbV9BXHQVuSuyVq7zMjO16wSExw== + dependencies: + dequal "^2.0.3" + use-sync-external-store "^1.6.0" + symbol-observable@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -17707,6 +19018,11 @@ throat@^6.0.1: resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== +throttleit@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-2.1.0.tgz#a7e4aa0bf4845a5bd10daa39ea0c783f631a07b4" + integrity sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw== + through2@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -18089,10 +19405,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@^4.9.5: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== typo-js@*: version "1.3.2" @@ -18149,6 +19465,11 @@ undici-types@~8.3.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-8.3.0.tgz#44e9fc9f3244648cdea35e4f9bb2d681e9410809" integrity sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ== +undici@^7.28.0: + version "7.29.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-7.29.0.tgz#ae0f6f62e06e057a9cbb7b2b5fde2bb74f791b8f" + integrity sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" @@ -18419,18 +19740,30 @@ url@^0.11.0: punycode "^1.4.1" qs "^6.12.3" -use-callback-ref@^1.3.0: +use-callback-ref@^1.3.0, use-callback-ref@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf" integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg== dependencies: tslib "^2.0.0" -use-isomorphic-layout-effect@^1.2.0: +use-composed-ref@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.4.0.tgz#09e023bf798d005286ad85cd20674bdf5770653b" + integrity sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w== + +use-isomorphic-layout-effect@^1.1.1, use-isomorphic-layout-effect@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz#2f11a525628f56424521c748feabc2ffcc962fce" integrity sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA== +use-latest@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.3.0.tgz#549b9b0d4c1761862072f0899c6f096eb379137a" + integrity sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ== + dependencies: + use-isomorphic-layout-effect "^1.1.1" + use-resize-observer@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/use-resize-observer/-/use-resize-observer-9.1.0.tgz#14735235cf3268569c1ea468f8a90c5789fc5c6c" @@ -18438,7 +19771,7 @@ use-resize-observer@^9.1.0: dependencies: "@juggle/resize-observer" "^3.3.1" -use-sidecar@^1.1.2: +use-sidecar@^1.1.2, use-sidecar@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb" integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ== @@ -18446,7 +19779,7 @@ use-sidecar@^1.1.2: detect-node-es "^1.1.0" tslib "^2.0.0" -use-sync-external-store@^1.0.0, use-sync-external-store@^1.4.0: +use-sync-external-store@^1.0.0, use-sync-external-store@^1.4.0, use-sync-external-store@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== @@ -19397,6 +20730,16 @@ yup@^1.7.1: toposort "^2.0.2" type-fest "^2.19.0" +zod@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.4.3.tgz#b680f172885d18bbebf21a834ea25e55a1bbf356" + integrity sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ== + +zustand@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.15.tgz#42bddf35647cb80a818a8943a69f6618c126fcfe" + integrity sha512-MpSEjRiBkA9crSYeOUH32rJC7SVqAbm0Fqcqge/bUi2PPoLcBWKOsG+C8mevmpr8TwXHBVkChbbJiyvkE+i/3A== + zwitch@^2.0.0, zwitch@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" From dd37c2907b89db84b3516492bb6b9eb66f42338f Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Thu, 27 Aug 2026 13:35:02 +0300 Subject: [PATCH 2/2] add adr 1 --- docs/adr/0001-topscout-rag-management.md | 223 +++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 docs/adr/0001-topscout-rag-management.md diff --git a/docs/adr/0001-topscout-rag-management.md b/docs/adr/0001-topscout-rag-management.md new file mode 100644 index 000000000..51627469d --- /dev/null +++ b/docs/adr/0001-topscout-rag-management.md @@ -0,0 +1,223 @@ +# ADR 0001 — TopScout RAG Management admin page + +- **Status:** Proposed — for review +- **Date:** 2026-08-27 +- **Repos affected:** `platform-ui` (this ADR, admin UI), `tc-ai-api` (two new HTTP endpoints — companion implementation work tracked here since the UI cannot ship without them) +- **Related:** + - `tc-ai-api` ADR 0004 — role-based access control for agents/workflows/tools (Proposed, same date). Restricts `challenge-ingestion`/`challenge-bulk-ingestion` to `roles: ['administrator']` / `scopes: ['challengesRAG:admin']` by default and introduces the reusable `checkAccess`/`toAuthenticatedCaller` policy core this ADR depends on. + - `tc-ai-api/src/mastra/agents/challenge/challenge-search-agent.ts` — the TopScout agent this page's index feeds. + - `tc-ai-api/src/mastra/workflows/challenge/challenge-ingestion-workflow.ts`, `challenge-bulk-ingestion-workflow.ts` — the two workflows this page drives. + - `platform-ui/src/libs/shared/lib/services/ai-workflows.tsx` — existing shared workflow-run/poll helper, already used for single-challenge ingestion. + - `platform-ui/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx` — existing single-challenge "Upsert for TopScout" action (toast-driven), the nearest prior art in this repo. + - `platform-ui/src/apps/admin/src/ai/review-workflows/AiReviewWorkflowsPage.tsx` — page-shell precedent this ADR follows (list + filter + confirm-modal architecture). + - `platform-ui/src/apps/customer-portal/src/pages/talent-search/TalentSearchPage/TalentSearchPage.tsx` — loading-state precedent for a blocking AI action (`isExtractingSkills` boolean + label swap), reused for the bulk-ingestion "run" state. + +## Context + +### What TopScout's RAG pipeline looks like today + +`challenge-search-agent` (id `challenge-search-agent`) answers questions by querying a PgVector index (`PgVector`, `@mastra/pg`) whose default name is **`challenge_embeddings`**, in schema `ai` (`MASTRA_DB_SCHEMA`, default `ai`), created and dimension-guarded lazily by `ensureChallengeIndex()` (`tc-ai-api/src/mastra/vector/challenge-vector-store.ts`). One challenge produces many rows — one per description chunk — each row's `metadata` JSONB carrying `challengeId`, `name`, `type`, `track`, `skills`, `groups`, `projectId`, `chunkIndex`/`totalChunks`, `text`, `ingestedAt`. `type`/`track` are free-form strings, never enum-validated (`rag.config.ts`'s D12), though `rag.config.ts` does export an *informational* `KNOWN_TYPES`/`KNOWN_TRACKS` pair for readability. `metadataIndexes: ['challengeId', 'projectId', 'track']` are the only three JSONB paths currently btree-indexed. + +Two Mastra workflows populate this index: +- `challenge-ingestion` (id `challenge-ingestion`) — one challenge, by id or inline record: resolve → chunk/embed the **public** description only → `store.upsert({ ..., deleteFilter: { challengeId } })` (atomic per-challenge replace). +- `challenge-bulk-ingestion` (id `challenge-bulk-ingestion`) — paginates `searchChallengesTool` over a filter (`status`, `projectId`, `types`, `tracks`, `tags`, `groups`, `updatedDateStart`), fans out `challenge-ingestion` per match (bounded concurrency), aggregates a report (`processed`/`succeeded`/`failed`/`skipped`/`totalChunks`/`forceSplits`/per-challenge `results[]`). + +Both are exposed over Mastra's native HTTP surface (`POST /v6/ai/workflows/:workflowId/create-run` → `.../start?runId=` → poll `GET /v6/ai/workflows/:workflowId/runs/:runId`), and `tc-ai-api` ADR 0004 (Proposed) is independently restricting both to `administrator`/`challengesRAG:admin` by default, precisely because a bulk run "re-embeds and rewrites the shared vector index for every challenge matching a filter." + +**What's missing, concretely:** +- No bulk-ingestion trigger anywhere in `platform-ui` — only the single-challenge path exists (`ingestChallengeInRag()` in the shared `ai-workflows.tsx`, wired into `ChallengeList.tsx`'s row-action dropdown as "Upsert for TopScout," toast-driven, one challenge at a time). +- No visibility into what's actually indexed. `PgVector` has no "list distinct challenges" API — it's a chunk-grained key-value/vector store, not a relational read model — so nothing today can answer "which challenges are in the RAG index, for which project, how many chunks." +- No delete path. `PgVector.deleteVectors({ indexName, filter })` (metadata-filtered delete) already exists in the SDK the code depends on, but nothing in `tc-ai-api` calls it, and there's no HTTP route to reach it. A challenge that's cancelled, deleted, or re-scoped in the source system stays searchable by TopScout indefinitely with no way to remove it short of a manual DB operation. + +### Where this page belongs + +`platform-ui`'s admin app already has a system-admin "AI" tab group (`aiRouteId = 'ai'` in `src/apps/admin/src/config/routes.config.ts`) with two children — Review Workflows (`aiReviewWorkflowsRouteId`) and Review Templates (`aiReviewTemplatesRouteId`) — registered as an ``-wrapped `children` block in `admin-app.routes.tsx`, gated by `rolesRequired: administratorOnlyRoles` on that parent node, and surfaced in `SystemAdminTabsConfig` (`src/apps/admin/src/lib/components/common/Tab/config/system-admin-tabs-config.ts`) gated a second time by `isAdministrator(roles)` in `getSystemAdminTabs()`. This is the exact shape the user's requested location (`/system-admin/ai/TopScout-RAG`) already matches — a third child under the same `aiRouteId` node, inheriting the same `administrator`-only gate with zero new frontend authorization code. (This ADR normalizes the path segment to `topscout-rag`, lower-kebab-case, matching the sibling `review-workflows`/`review-templates` convention rather than the mixed-case form in the request.) + +### Access control is a genuine cross-repo dependency, not a UI nicety + +The two capabilities this page adds — bulk-(re)ingest and delete-from-index — are at least as sensitive as `challenge-bulk-ingestion` itself (same shared-index blast radius; delete is one-way against the only copy of that data). `tc-ai-api` ADR 0004's own enforcement design only recognizes `/v6/ai/agents/:id/*`, `/v6/ai/workflows/:id/*`, and `/v6/ai-chat/:agentId` shapes in its URL-pattern matcher (`authorizeAccessPolicy`) — a plain custom route like `/v6/ai/challenge-embeddings/*` falls through that matcher's "no match → true" branch and would be **authenticated-but-unrestricted** by default if nothing else is done, exactly the kind of silent gap ADR 0004 itself flags as a standing footgun for future resources. This ADR does not relitigate ADR 0004's design; it reuses its policy primitives directly at the two new route handlers' call sites (see Decision 2), the same way ADR 0004 itself wraps tools at their own export site rather than relying purely on the HTTP-boundary matcher. + +## Scope + +**In scope:** +- A new admin page, `TopScout RAG` (`/system-admin/ai/topscout-rag`), as a third child of the existing `aiRouteId` system-admin tab. +- **Ingestion panel**: trigger a single-challenge or filtered bulk-ingestion run against `challenge-ingestion`/`challenge-bulk-ingestion`, monitor it to completion via the existing poll helper, and present a completion summary (counts, per-challenge failures) or a clear error. +- **Indexed-challenges panel**: a paginated, filterable (project, track, type), searchable list of what `challenge_embeddings` currently holds, with a per-row Delete action (confirm-modal gated) that removes that challenge's vectors from the index. +- Exactly two new `tc-ai-api` HTTP endpoints, both under the existing `/v6/ai` prefix: + - `DELETE /v6/ai/challenge-embeddings/:challengeId` + - `GET /v6/ai/challenge-embeddings` (list + count + filtering + search — the single "stats/count" endpoint requested; see Decision 2 for why this is one endpoint, not a separate stats/facets endpoint) +- Extending the shared `platform-ui` workflow-run service with bulk-ingestion support, and a small new admin-app service for the two new endpoints. +- Reusing (not redefining) `tc-ai-api` ADR 0004's access-control primitives to gate the two new endpoints with the same default policy as the two ingestion workflows. + +**Out of scope (deferred, not rejected):** +- Automatic re-ingestion (e.g., a challenge-update webhook calling `challenge-ingestion`) — this page is manual/on-demand only. +- Scheduled/cron-driven bulk ingestion. +- A resolved project-name picker for the project filter — v1 filters by bare project id (see Decision 4); TopScout's own agent treats `projectId` as an opaque, never-dereferenced reference (D10) for the same reason, and this page follows that precedent rather than adding a new projects-api dependency for a filter control. +- In-place editing of an indexed challenge's content — re-ingestion is the only way to change what's indexed; this page never writes challenge content itself. +- Any change to ADR 0004's own decisions — this ADR is a consumer of that policy core, not a revision of it (see Decision 2 and Open Questions for sequencing). + +## Decision + +### 1. Page placement and route wiring (`platform-ui`) + +- `src/apps/admin/src/config/routes.config.ts`: add `export const topScoutRagRouteId = 'topscout-rag'`. +- `src/apps/admin/src/admin-app.routes.tsx`: lazy-load `TopScoutRagPage` (`./ai/topscout-rag/TopScoutRagPage`) and add it as a third entry in the existing `aiRouteId` block's `children` array, alongside `AiReviewWorkflowsPage`/`AiReviewTemplatesPage` — no new `rolesRequired` needed; it inherits the parent `aiRouteId` node's `administratorOnlyRoles`. +- `src/apps/admin/src/lib/components/common/Tab/config/system-admin-tabs-config.ts`: add `{ id: `${aiRouteId}/${topScoutRagRouteId}`, title: 'TopScout RAG' }` to the existing `aiRouteId` tab's `children` array (next to "AI Review Workflows"/"AI Review Templates"). +- Page files: `src/apps/admin/src/ai/topscout-rag/TopScoutRagPage.tsx` (+ `.module.scss`, `index.ts`), following `AiReviewWorkflowsPage.tsx`'s shell exactly: `PageWrapper` wrapping (a) the ingestion panel and (b) `TableLoading` / `TableNoRecord` / `TableWrapper` / `Table` / `TableMobile` for the indexed-challenges list, all pulled from the admin app's existing `../../lib` barrel — no new shared UI primitives required. + +### 2. `tc-ai-api`: exactly two new endpoints, and why not three + +The request asks for delete-by-id plus "a stats/count endpoint which should provide the list of challenges, count and project, [with] filtering... and searching." That is one endpoint doing list+count+filter+search, not a separate facets endpoint for populating filter dropdowns. To keep it at exactly two endpoints: + +- **Project filter**: plain project-id text/number input, not a resolved picker (Scope, Decision 4) — no facet needed. +- **Type/Track filter options**: sourced from a small duplicated constant in `platform-ui` (`TOPSCOUT_RAG_KNOWN_TYPES`/`TOPSCOUT_RAG_KNOWN_TRACKS`, mirroring `tc-ai-api`'s `rag.config.ts` `KNOWN_TYPES`/`KNOWN_TRACKS` values verbatim, with a comment pointing at that file as source of truth) rather than a live `SELECT DISTINCT` facet query. This is safe specifically because `rag.config.ts` already documents these two lists as **informational only, not enforced** (D12) — a stale dropdown option is a minor UX gap (an admin can't filter by a value that predates this constant list), never a correctness bug, since the list/search query itself matches whatever free-form value a row actually has regardless of what the dropdown offers. (Note this dropdown is intentionally broader than the vector-*search* tool's own type enum — `challenge-search-agent`'s instructions restrict its search-time `type` filter to only `"Challenge"`/`"Marathon Match"` — because this page browses everything that was ever indexed, not just what the chat agent can query by type.) + +New module `tc-ai-api/src/mastra/vector/challenge-embeddings-admin.ts` (co-located with the existing `challenge-vector-store.ts`, reusing its lazy `getChallengeVectorStore()`/`ensureChallengeIndex()` singleton): + +```ts +export async function deleteChallengeEmbeddings(challengeId: string): Promise<{ deletedChunks: number }> { + const config = getRagConfig(); + const store = await ensureChallengeIndex(); + const { rows } = await store.pool.query( + `SELECT COUNT(*)::int AS n FROM "${schemaIdent(config)}"."${config.vectorIndexName}" WHERE metadata->>'challengeId' = $1`, + [challengeId], + ); + const deletedChunks = rows[0]?.n ?? 0; + if (deletedChunks > 0) { + await store.deleteVectors({ indexName: config.vectorIndexName, filter: { challengeId } }); + } + return { deletedChunks }; +} + +export async function listChallengeEmbeddings(params: { + projectId?: string; track?: string; type?: string; search?: string; + page: number; perPage: number; +}): Promise<{ items: ChallengeEmbeddingSummary[]; total: number }> { + // GROUP BY metadata->>'challengeId', with a parameterized WHERE built from + // the optional filters (never string-concatenated — only the validated + // schema/index identifiers are interpolated; every filter *value* is a + // bound $n param); a second COUNT(DISTINCT metadata->>'challengeId') + // query (same WHERE, no GROUP BY / LIMIT) for `total`. +} +``` + +`PgVector.deleteVectors({ indexName, filter, ids, namespace })` and the public `pool: pg.Pool` field are both already part of the installed `@mastra/pg@1.22.0` surface — confirmed by reading `dist/vector/index.d.ts` directly rather than assumed. `deleteVectors` gives the atomic metadata-filtered delete the DELETE endpoint needs for free; `pool` is the only way to do the chunk-grained-to-challenge-grained `GROUP BY` aggregation the list endpoint needs, since `PgVector` itself has no "distinct records" query shape. + +Two follow-on, additive, idempotent changes this decision requires: +- `ensureChallengeIndex()`'s existing `metadataIndexes: ['challengeId', 'projectId', 'track']` gains `'type'`, so the new list/filter query isn't an unindexed scan on the one JSONB path it's missing. `createIndex()` is already called unconditionally on every boot per that function's own doc comment ("safe to call every time"), so this is a one-line, zero-migration addition. +- The schema name (`MASTRA_DB_SCHEMA`, default `ai`) is validated with the same `validateSqlIdentifier()` regex `rag.config.ts` already applies to `VECTOR_INDEX_NAME`, at the point this new module builds its raw SQL identifiers — `rag.config.ts` itself does not currently validate `schemaName`, and this module is the first place in the codebase to interpolate it directly into a SQL string, so it must not inherit that gap silently. + +**Route registration** (`tc-ai-api/src/mastra/index.ts`, `server.apiRoutes` array, alongside the existing `chatRoute(...)` entry): both new routes are registered via Mastra's `registerApiRoute` (`@mastra/core/server`) under `${API_PREFIX}/challenge-embeddings` (GET, list) and `${API_PREFIX}/challenge-embeddings/:challengeId` (DELETE). Both are automatically **authenticated** by `apiAuthLayer`'s existing `protected: ['${API_PREFIX}/*']` blanket rule — no change needed there. Neither is automatically **authorized** by ADR 0004's `authorizeAccessPolicy`, since its path matcher only recognizes `/agents/`, `/workflows/`, and chatRoute shapes (Context, above). Each handler therefore calls the same policy check ADR 0004 exports, at the top of its own body — mirroring how ADR 0004 wraps tools at their *own* export site rather than relying solely on the HTTP boundary: + +```ts +// inside each of the two new route handlers +if (process.env.DISABLE_AUTH !== 'true') { + const user = /* from context, same as resourceIdMiddleware's resolution */; + const policy = resolveAccessPolicy('route', 'challenge-embeddings-admin'); // new AccessCategory + if (!user || !checkAccess(toAuthenticatedCaller(user), policy)) { + return c.json({ error: 'Forbidden' }, 403); + } +} +``` + +This adds one new entry to ADR 0004's own `DEFAULT_ACCESS_POLICIES` registry — a third `AccessCategory` (`'route'`) alongside `agent`/`workflow`/`tool` — rather than a silently-hardcoded, unregistered check, so the new capability stays visible in the same reviewable place ADR 0004 established: + +```ts +route: { + 'challenge-embeddings-admin': { mode: 'restricted', roles: ['administrator'], scopes: ['challengesRAG:admin'] }, +}, +``` + +Both the list (`GET`) and delete (`DELETE`) endpoints use the **same** restricted policy — the list endpoint is not left `public` even though it's read-only, because it lets a caller enumerate every currently-indexed challenge (name/project/track/type) in one shot, which is a wider disclosure surface than the per-challenge, already-public data `challenge-vector-query` exposes one hit at a time. This mirrors ADR 0004's own choice to restrict both ingestion workflows uniformly rather than splitting by read/write. + +**Response shape** (`GET`): body is a **plain array** of `{ challengeId, name, type, track, projectId, groups, skills, chunkCount, ingestedAt }`; pagination rides on `X-Page`/`X-Per-Page`/`X-Total`/`X-Total-Pages` **response headers** — already present in `tc-ai-api`'s existing CORS `exposeHeaders` list (`src/mastra/index.ts`) and exactly what `platform-ui`'s existing `xhrGetPaginatedAsync` (`src/libs/core/lib/xhr/xhr-functions/xhr.functions.ts`, reading `x-page`/`x-per-page`/`x-total`) already parses. The frontend needs zero new pagination-parsing code for this endpoint — only a new URL and query params. + +### 3. `platform-ui`: service layer + +- `src/libs/shared/lib/services/ai-workflows.tsx`: add `ingestChallengesBulkInRag(filters, workflowId?)`, mirroring `ingestChallengeInRag`'s existing shape (`startWorkflowRun` → `pollWorkflowRunStatus`, both already generic over any workflow id) and a new `normalizeChallengeBulkIngestionResult()`/`ChallengeBulkIngestionResult` type mirroring the workflow's own `bulkReportSchema` (`processed`/`succeeded`/`failed`/`skipped`/`totalChunks`/`results[]`). No changes to `startWorkflowRun`/`pollWorkflowRunStatus` themselves — both are already workflow-agnostic. +- New env var `RAG_CHALLENGE_BULK_INGESTION_WORKFLOW_ID` (`default.env.ts` + `global-config.model.ts`), defaulting to **`'challenge-bulk-ingestion'`** — the workflow's own `.id`. This is a deliberate departure from the sibling `RAG_CHALLENGE_INGESTION_WORKFLOW_ID`'s existing default (`'challengeIngestionWorkflow'`, the Mastra *registry key*, not the `.id`) already shipped in this codebase: per ADR 0004's own documented footgun, keying on the registry key instead of `.id` only happens to work today because `Mastra.getAgentById()`/workflow routing falls back from `.id` to registry key on a miss — it is not something a new addition should copy forward as if it were the correct convention. +- New `src/apps/admin/src/lib/services/challenge-embeddings.service.ts`, matching the existing `ai-workflows.service.ts` pattern in the same directory: `getChallengeEmbeddings(params)` via `xhrGetPaginatedAsync(...)`, `deleteChallengeEmbeddings(challengeId)` via `xhrDeleteAsync`. + +### 4. Page behavior + +**Ingestion panel** — a small form: either a single free-text challenge-id field, or the bulk filter set (`projectId`, `track`, `type`, `status`, `updatedDateStart` — mirroring `challenge-bulk-ingestion`'s own `bulkInputSchema`), mutually exclusive the same way `challenge-ingestion`'s own resolve step requires exactly one source (challengeId XOR inline record) — the page enforces the analogous rule client-side (single-id field XOR any filter field) before allowing Run. A "Dry run" toggle passes straight through to the workflow's existing `dryRun` input (chunk+embed, skip the upsert) — useful for previewing a bulk run's scope before committing it. Flow on Run: +1. `ConfirmModal` (bulk ingestion mutates the shared index for every match — the same reason ADR 0004 restricts it server-side; the UI asks before firing, not as a substitute for that server-side enforcement, but because it's a slow, hard-to-abort action worth a deliberate click). +2. `isRunning` boolean disables the form and swaps the button label (`"Ingesting…"` / `"Running bulk ingestion…"`), matching `TalentSearchPage.tsx`'s `isExtractingSkills` idiom — no separate blocking modal is needed, since `pollWorkflowRunStatus` already blocks the returned promise until the run resolves. +3. On resolve: a per-run **completion summary** stays visible in the panel (processed / succeeded / failed / skipped / total chunks, plus an expandable list of `results.filter(r => r.status === 'failed')` with each failure's message) — richer than a toast alone, since a bulk run has much more to report than the single-challenge case. `toast.success`/`toast.error` still fires for the at-a-glance case, matching `ChallengeList.tsx`'s existing toast idiom for the single-ingest action. +4. A successful run (bulk or single) triggers a refetch of the indexed-challenges list below, so newly (re-)ingested challenges show up without a manual refresh. + +**Indexed-challenges panel** — `getChallengeEmbeddings({ page, perPage, projectId, track, type, search })` on mount and on any filter change; columns: Challenge (name, linking to `${EnvironmentConfig.ADMIN.CHALLENGE_URL}/${challengeId}`, matching `ChallengeList.tsx`'s existing external-link convention), Type, Track, Project (bare id, per Decision 4/Scope), Chunks, Ingested At, and a Delete action. Delete opens the same `ConfirmModal` pattern `AiReviewWorkflowsPage.tsx` already uses for its activate/deactivate confirmation, calls `deleteChallengeEmbeddings(challengeId)`, toasts on result, and removes the row (or refetches the current page) on success. + +## Implementation plan + +### Phase 0 — `tc-ai-api`: data-layer additions +- `challenge-vector-store.ts`: add `'type'` to `metadataIndexes`. +- New `challenge-embeddings-admin.ts`: `deleteChallengeEmbeddings()`, `listChallengeEmbeddings()`, schema-identifier validation at the point of use. +- Unit tests mirroring `challenge-vector-store.test.ts`'s existing conventions: delete removes exactly the matched challenge's rows and reports an accurate `deletedChunks` (including the "nothing matched" / `0` case); list respects each filter independently and in combination; search matches by name substring and by exact challengeId; pagination math (`total`, `page`/`perPage` boundaries) is correct against a seeded multi-challenge, multi-chunk fixture. + +### Phase 1 — `tc-ai-api`: routes and access control +- Extend ADR 0004's `AccessCategory`/`DEFAULT_ACCESS_POLICIES` with the `route` category and the `challenge-embeddings-admin` entry (Decision 2). If ADR 0004 has not yet merged when this phase starts, land the equivalent inline `checkAccess`/`toAuthenticatedCaller` call directly in the two new handlers with the hardcoded restricted policy, and switch to the shared registry in a follow-up once ADR 0004 ships — sequencing note, not a blocker (see Open Questions). +- Register the two routes in `mastra/index.ts`'s `apiRoutes`. +- Tests mirroring ADR 0004's own planned `resourceIdMiddleware.test.ts` cases: member without `administrator` → 403; member with it → 200; M2M without `challengesRAG:admin` → 403; M2M with it → 200; `DISABLE_AUTH=true` bypasses both. + +### Phase 2 — `platform-ui`: service layer +- `ai-workflows.tsx`: `ingestChallengesBulkInRag()`, `ChallengeBulkIngestionResult`. +- `default.env.ts` / `global-config.model.ts`: `RAG_CHALLENGE_BULK_INGESTION_WORKFLOW_ID`. +- New `challenge-embeddings.service.ts` in the admin app. + +### Phase 3 — `platform-ui`: page +- Route/tab wiring (Decision 1). +- `TopScoutRagPage.tsx` — ingestion panel + indexed-challenges panel, per Decision 4. +- Manual smoke test in a real environment (per this repo's own "verify against the running system, don't assume" precedent): run a small bulk ingestion with a narrow filter, confirm the summary matches what actually landed in the index, confirm a subsequent list-page fetch shows it, delete it, confirm it disappears from the list and TopScout itself can no longer surface it in a follow-up chat query. + +### Phase 4 — Documentation +- `tc-ai-api README.md`: document the two new routes next to the existing workflow/agent route documentation. +- `platform-ui`: no README currently documents the admin AI tab group's routes; none added here either, consistent with the existing sibling pages. + +## File-level mapping + +| Repo | File | Change | +| --- | --- | --- | +| tc-ai-api | `src/mastra/vector/challenge-vector-store.ts` | Modified — add `'type'` to `metadataIndexes` | +| tc-ai-api | `src/mastra/vector/challenge-embeddings-admin.ts` | New — `deleteChallengeEmbeddings`, `listChallengeEmbeddings` | +| tc-ai-api | `src/mastra/vector/challenge-embeddings-admin.test.ts` | New | +| tc-ai-api | `src/config/access-control.config.ts` | Modified (ADR 0004 dependency) — `route` category, `challenge-embeddings-admin` policy entry | +| tc-ai-api | `src/mastra/index.ts` | Modified — register the two new `apiRoutes` | +| tc-ai-api | `README.md` | Modified — document the two new routes | +| platform-ui | `src/libs/shared/lib/services/ai-workflows.tsx` | Modified — `ingestChallengesBulkInRag`, `ChallengeBulkIngestionResult` | +| platform-ui | `src/config/environments/default.env.ts` | Modified — `RAG_CHALLENGE_BULK_INGESTION_WORKFLOW_ID` | +| platform-ui | `src/config/environments/global-config.model.ts` | Modified — same | +| platform-ui | `src/apps/admin/src/lib/services/challenge-embeddings.service.ts` | New | +| platform-ui | `src/apps/admin/src/config/routes.config.ts` | Modified — `topScoutRagRouteId` | +| platform-ui | `src/apps/admin/src/admin-app.routes.tsx` | Modified — new lazy route under `aiRouteId` | +| platform-ui | `src/apps/admin/src/lib/components/common/Tab/config/system-admin-tabs-config.ts` | Modified — new child tab | +| platform-ui | `src/apps/admin/src/ai/topscout-rag/TopScoutRagPage.tsx` (+ `.module.scss`, `index.ts`) | New | +| platform-ui | `src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx` | **Unchanged** — its existing single-ingest action is independent of this page and stays as-is | + +## Consequences + +**Positive** +- Admins get a real operational surface for the RAG pipeline — bulk backfill/re-ingest, visibility into what's actually indexed, and a way to remove stale entries — none of which exists today short of a manual DB operation. +- Reuses, rather than duplicates, three separate pieces of prior art in this codebase: the shared workflow-run/poll service, the admin app's existing list-page shell (`AiReviewWorkflowsPage.tsx`), and the existing `xhrGetPaginatedAsync` header-based pagination contract — net-new frontend code is small. +- The two new endpoints stay inside `tc-ai-api`'s existing route/auth/CORS conventions (same `apiPrefix`, same `exposeHeaders`, same `apiRoutes` registration point as `chatRoute`) rather than introducing a parallel pattern. +- Explicitly re-uses ADR 0004's access-control model instead of inventing a second one, keeping "who can touch the RAG index" answerable from one registry. + +**Negative / risk** +- **Two-repo dependency for one feature.** This page cannot function until both new `tc-ai-api` endpoints ship; sequencing must be tracked explicitly (see Implementation plan phasing) rather than assumed. +- **Depends on an ADR that is itself still Proposed.** If ADR 0004's shape changes before it merges, Decision 2's `route` category / registry entry needs to move with it. Mitigated by keeping the inline-fallback option explicit in Phase 1 rather than hard-blocking on ADR 0004 merging first. +- **`KNOWN_TYPES`/`KNOWN_TRACKS` duplication is a manually-maintained mirror**, not a shared import (the two repos don't share a package for this). A future addition to `rag.config.ts`'s lists won't automatically appear in this page's filter dropdown. Accepted per Decision 2's reasoning (informational-only, non-enforced, UX-only staleness) rather than adding a third endpoint to keep them in sync live. +- **Raw SQL against `store.pool`** is new surface in a codebase that otherwise only talks to Postgres through `PgVector`'s own methods. Every filter/search *value* is a bound parameter; only the already-validated `vectorIndexName`/`schemaName` identifiers are ever interpolated — but this is still the first hand-written SQL in the vector layer, worth an explicit review pass, not just a "matches existing patterns" assumption. +- **Delete is irreversible.** There is no soft-delete or undo — removing a challenge's vectors means the next chat query about it returns nothing until it's re-ingested. The confirm-modal step is the only guard; this ADR does not add an audit trail beyond `tc-ai-api`'s existing `tcAILogger` usage (matching ADR 0004's own "single structured log line" precedent for denials — an actual delete, not just a denial, should log at `info` with the challengeId and caller for the same reason). + +## Open questions + +- **Sequencing with ADR 0004**: does this ADR's `tc-ai-api` work land before, after, or alongside ADR 0004's own implementation? Phase 1 above describes both orders; whichever happens first should not block the other, but the final registry shape (Decision 2) is only settled once ADR 0004 itself is no longer Proposed. +- Should the project filter graduate from a bare-id input to a resolved project-name picker once real admin usage shows bare ids are hard to work with? Deferred per Scope; revisit with actual usage feedback rather than speculatively building it now. +- Should `type`/`track` filter options move from the duplicated constant to a live facet query if the two lists drift in practice? Deferred per Decision 2/Consequences; only worth the extra endpoint if the duplication actually causes friction. +- Does a future webhook-driven auto-(re)ingestion pipeline reduce this page's bulk-ingestion panel to a "manual override / backfill only" tool? Out of scope here either way, but worth naming so a future ADR doesn't have to rediscover the relationship. + +## Prerequisites to confirm before implementation starts + +- The `administrator` role / `challengesRAG:admin` M2M scope convention from `tc-ai-api` ADR 0004 must actually exist in the relevant Auth0 tenant before either new endpoint's restriction is meaningful — this ADR reuses that prerequisite rather than re-verifying it independently. +- Confirm `challenge-bulk-ingestion` is reachable by its own `.id` (`RAG_CHALLENGE_BULK_INGESTION_WORKFLOW_ID`'s default) against a real deployed `tc-ai-api` — expected to work per Mastra's documented `.id`-first routing, but this ADR's own Decision 3 calls out that a sibling env var's default currently relies on registry-key fallback instead, so a live smoke test is cheap insurance rather than a formality. +- Reviewer sign-off on: adding a third `route` category to ADR 0004's access-control registry from a second ADR (Decision 2) rather than that decision living entirely inside ADR 0004 itself; the "duplicate the two known-value constants instead of a third facets endpoint" trade-off (Decision 2/Consequences); and the "list endpoint is restricted, not public" choice given it's read-only (Decision 2).