From bde2decd9ea8ce237ec39c760e70268d9cde4dd5 Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 7 Dec 2025 22:47:35 -0800 Subject: [PATCH] new integrated hugginface model search, ensure that prettier --check is run in CI --- .github/workflows/ci.yml | 2 +- index.html | 2 +- package.json | 9 +- src/components/Modal.tsx | 80 +- .../screens/Launch/GeneralTab/index.tsx | 6 +- .../HuggingFaceSearchModal/FilesTable.tsx | 56 + .../HuggingFaceSearchModal/ModelCard.tsx | 107 ++ .../HuggingFaceSearchModal/ModelsTable.tsx | 138 ++ .../Launch/HuggingFaceSearchModal/index.tsx | 235 ++++ .../screens/Launch/ImageGenerationTab.tsx | 44 +- .../screens/Launch/ModelFileField.tsx | 26 +- src/components/settings/SettingsModal.tsx | 191 ++- src/constants/imageModelPresets.ts | 47 +- src/constants/index.ts | 5 +- src/hooks/useHuggingFaceSearch.ts | 356 +++++ src/main/modules/koboldcpp/config.ts | 32 +- src/types/index.d.ts | 29 + src/utils/format.ts | 19 + yarn.lock | 1174 ++++++++++++++++- 19 files changed, 2345 insertions(+), 213 deletions(-) create mode 100644 src/components/screens/Launch/HuggingFaceSearchModal/FilesTable.tsx create mode 100644 src/components/screens/Launch/HuggingFaceSearchModal/ModelCard.tsx create mode 100644 src/components/screens/Launch/HuggingFaceSearchModal/ModelsTable.tsx create mode 100644 src/components/screens/Launch/HuggingFaceSearchModal/index.tsx create mode 100644 src/hooks/useHuggingFaceSearch.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64ae033..cdb005f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: - name: Install dependencies run: yarn - - name: Run checks (lint, type check, spell check) + - name: Run checks (format, lint, type check) run: yarn test - name: Test build diff --git a/index.html b/index.html index f8c7657..0754bea 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ Gerbil diff --git a/package.json b/package.json index a263cbc..0e0d21a 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,11 @@ "package": "electron-vite build && electron-builder --publish=never", "analyze": "cross-env ANALYZE=true electron-vite build && yarn dlx open-cli dist/stats.html", "format": "prettier --write . --ignore-path .gitignore | grep -v '(unchanged)' || true", + "format:check": "prettier --check . --ignore-path .gitignore", "lint": "eslint .", "lint:fix": "eslint . --fix", "compile": "tsc --noEmit", - "test": "yarn lint && yarn compile", + "test": "yarn format:check && yarn lint && yarn compile", "release": "yarn dlx tsx scripts/release.ts" }, "keywords": [ @@ -53,6 +54,10 @@ "react": "^19.2.1", "react-dom": "^19.2.1", "react-error-boundary": "^6.0.0", + "react-markdown": "^10.1.0", + "rehype-raw": "^7.0.0", + "rehype-sanitize": "^6.0.0", + "remark-gfm": "^4.0.1", "systeminformation": "^5.27.11", "winston": "^3.19.0", "winston-daily-rotate-file": "^5.0.0", @@ -85,7 +90,7 @@ "prettier": "^3.7.4", "rollup-plugin-visualizer": "^6.0.5", "typescript": "^5.9.3", - "vite": "^7.2.6" + "vite": "^7.2.7" }, "build": { "appId": "com.gerbil.app", diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 86c3f10..e68dd26 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -21,6 +21,7 @@ export interface ModalProps { closeOnClickOutside?: boolean; closeOnEscape?: boolean; showCloseButton?: boolean; + tallContent?: boolean; } export const Modal = ({ @@ -32,33 +33,54 @@ export const Modal = ({ closeOnClickOutside = false, closeOnEscape = true, showCloseButton = false, + tallContent = false, ...props -}: ModalProps) => ( - - {children} - {showCloseButton && ( - - - - )} - -); +}: ModalProps) => { + const content = tallContent ? ( +
+ {children} +
+ ) : ( + <> + {children} + {showCloseButton && ( + + + + )} + + ); + + return ( + + {content} + + ); +}; diff --git a/src/components/screens/Launch/GeneralTab/index.tsx b/src/components/screens/Launch/GeneralTab/index.tsx index 9afc915..cd0dd77 100644 --- a/src/components/screens/Launch/GeneralTab/index.tsx +++ b/src/components/screens/Launch/GeneralTab/index.tsx @@ -37,7 +37,11 @@ export const GeneralTab = ({ configLoaded = true }: GeneralTabProps) => { tooltip="Select a GGUF text generation model file for chat and completion tasks." onChange={setModel} onSelectFile={() => selectFile('model', 'Select Text Model')} - searchUrl="https://huggingface.co/models?pipeline_tag=text-generation&library=gguf&sort=trending" + searchParams={{ + pipelineTag: 'text-generation', + filter: 'gguf', + sort: 'trendingScore', + }} showAnalyze paramType="model" /> diff --git a/src/components/screens/Launch/HuggingFaceSearchModal/FilesTable.tsx b/src/components/screens/Launch/HuggingFaceSearchModal/FilesTable.tsx new file mode 100644 index 0000000..565f3fc --- /dev/null +++ b/src/components/screens/Launch/HuggingFaceSearchModal/FilesTable.tsx @@ -0,0 +1,56 @@ +import { Table, Text, Group, Loader } from '@mantine/core'; +import { formatBytes } from '@/utils/format'; +import type { HuggingFaceFileInfo } from '@/types'; + +interface FilesTableProps { + files: HuggingFaceFileInfo[]; + loading: boolean; + onSelect: (file: HuggingFaceFileInfo) => void; +} + +export const FilesTable = ({ files, loading, onSelect }: FilesTableProps) => { + if (loading) { + return ( + + + + ); + } + + if (files.length === 0) { + return ( + + No compatible files found in this model + + ); + } + + return ( + + + + File + Size + + + + {files.map((file) => ( + onSelect(file)} + style={{ cursor: 'pointer' }} + > + + + {file.path} + + + + {formatBytes(file.size)} + + + ))} + +
+ ); +}; diff --git a/src/components/screens/Launch/HuggingFaceSearchModal/ModelCard.tsx b/src/components/screens/Launch/HuggingFaceSearchModal/ModelCard.tsx new file mode 100644 index 0000000..8cefcff --- /dev/null +++ b/src/components/screens/Launch/HuggingFaceSearchModal/ModelCard.tsx @@ -0,0 +1,107 @@ +import { useState } from 'react'; +import { Accordion, Paper, Group, Loader, Text } from '@mantine/core'; +import ReactMarkdown from 'react-markdown'; +import remarkGfm from 'remark-gfm'; +import rehypeRaw from 'rehype-raw'; +import rehypeSanitize from 'rehype-sanitize'; +import { HUGGINGFACE_BASE_URL } from '@/constants'; + +interface ModelCardProps { + modelId: string; +} + +export const ModelCard = ({ modelId }: ModelCardProps) => { + const [readme, setReadme] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const loadReadme = async () => { + if (readme !== null) return; + setLoading(true); + setError(null); + try { + const response = await fetch( + `${HUGGINGFACE_BASE_URL}/${modelId}/raw/main/README.md` + ); + if (!response.ok) { + throw new Error('README not available'); + } + let text = await response.text(); + + const frontmatterRegex = /^---\n[\s\S]*?\n---\n/; + text = text.replace(frontmatterRegex, ''); + + setReadme(text); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to load README'); + } finally { + setLoading(false); + } + }; + + return ( + + + Model Card + + {loading && ( + + + + )} + {error && ( + + {error} + + )} + {readme && ( + + ( + + ), + pre: ({ node, ...props }) => ( +
+                  ),
+                  code: ({ node, ...props }) => (
+                    
+                  ),
+                }}
+              >
+                {readme}
+              
+            
+          )}
+        
+      
+    
+  );
+};
diff --git a/src/components/screens/Launch/HuggingFaceSearchModal/ModelsTable.tsx b/src/components/screens/Launch/HuggingFaceSearchModal/ModelsTable.tsx
new file mode 100644
index 0000000..b0fdb29
--- /dev/null
+++ b/src/components/screens/Launch/HuggingFaceSearchModal/ModelsTable.tsx
@@ -0,0 +1,138 @@
+import {
+  Table,
+  Text,
+  Group,
+  Loader,
+  Stack,
+  Badge,
+  Tooltip,
+} from '@mantine/core';
+import { Download, Heart, Lock } from 'lucide-react';
+import { HUGGINGFACE_BASE_URL } from '@/constants';
+import { formatDownloads, formatDate } from '@/utils/format';
+import type { HuggingFaceModelInfo, HuggingFaceSortOption } from '@/types';
+
+interface ModelsTableProps {
+  models: HuggingFaceModelInfo[];
+  loading: boolean;
+  onSelect: (model: HuggingFaceModelInfo) => void;
+  sortBy: HuggingFaceSortOption;
+  onSortChange: (sort: HuggingFaceSortOption) => void;
+}
+
+export const ModelsTable = ({
+  models,
+  loading,
+  onSelect,
+  sortBy,
+  onSortChange,
+}: ModelsTableProps) => {
+  if (loading && models.length === 0) {
+    return (
+      
+        
+      
+    );
+  }
+
+  if (models.length === 0) {
+    return (
+      
+        No models found
+      
+    );
+  }
+
+  return (
+    
+      
+        
+          Model
+          Params
+           onSortChange('downloads')}
+          >
+            Downloads{sortBy === 'downloads' && ' ↓'}
+          
+           onSortChange('likes')}
+          >
+            Likes{sortBy === 'likes' && ' ↓'}
+          
+        
+      
+      
+        {models.map((model) => (
+           {
+              if (model.gated) {
+                window.electronAPI.app.openExternal(
+                  `${HUGGINGFACE_BASE_URL}/${model.id}`
+                );
+              } else {
+                onSelect(model);
+              }
+            }}
+            style={{
+              cursor: 'pointer',
+            }}
+          >
+            
+              
+                
+                  
+                    {model.name}
+                  
+                  {model.gated && (
+                    
+                      }
+                      >
+                        Gated
+                      
+                    
+                  )}
+                
+                
+                  
+                    {model.author}
+                  
+                  
+                    •
+                  
+                  
+                    Updated {formatDate(model.updatedAt)}
+                  
+                
+              
+            
+            
+              {model.paramSize && (
+                
+                  {model.paramSize}
+                
+              )}
+            
+            
+              
+                
+                {formatDownloads(model.downloads)}
+              
+            
+            
+              
+                
+                {formatDownloads(model.likes)}
+              
+            
+          
+        ))}
+      
+    
+ ); +}; diff --git a/src/components/screens/Launch/HuggingFaceSearchModal/index.tsx b/src/components/screens/Launch/HuggingFaceSearchModal/index.tsx new file mode 100644 index 0000000..febf7a0 --- /dev/null +++ b/src/components/screens/Launch/HuggingFaceSearchModal/index.tsx @@ -0,0 +1,235 @@ +import { useEffect, useState, useRef } from 'react'; +import { + Stack, + TextInput, + Text, + Group, + ActionIcon, + Tooltip, + Badge, + Loader, + Alert, + ScrollArea, + SegmentedControl, +} from '@mantine/core'; +import { useDebouncedValue } from '@mantine/hooks'; +import { Search, ArrowLeft, ExternalLink } from 'lucide-react'; +import { Modal } from '@/components/Modal'; +import { useHuggingFaceSearch } from '@/hooks/useHuggingFaceSearch'; +import { HUGGINGFACE_BASE_URL } from '@/constants'; +import type { + HuggingFaceModelInfo, + HuggingFaceFileInfo, + HuggingFaceSortOption, + HuggingFaceSearchParams, +} from '@/types'; +import { ModelsTable } from './ModelsTable'; +import { FilesTable } from './FilesTable'; +import { ModelCard } from './ModelCard'; + +interface HuggingFaceSearchModalProps { + opened: boolean; + onClose: () => void; + onSelect: (url: string) => void; + searchParams: HuggingFaceSearchParams; +} + +export const HuggingFaceSearchModal = ({ + opened, + onClose, + onSelect, + searchParams: initialSearchParams, +}: HuggingFaceSearchModalProps) => { + const [searchQuery, setSearchQuery] = useState( + initialSearchParams.search || '' + ); + const [debouncedQuery] = useDebouncedValue(searchQuery, 300); + const scrollAreaRef = useRef(null); + const prevOpenedRef = useRef(false); + + const { + models, + files, + loading, + loadingFiles, + error, + hasMore, + selectedModel, + sortBy, + searchParams, + searchModels, + loadMoreModels, + loadModelFiles, + changeSortOrder, + getFileDownloadUrl, + reset, + } = useHuggingFaceSearch(initialSearchParams); + + const handleSortChange = (value: string) => { + changeSortOrder(value as HuggingFaceSortOption, searchQuery); + }; + + useEffect(() => { + if (opened && !prevOpenedRef.current) { + searchModels(); + } + if (!opened && prevOpenedRef.current) { + reset(); + } + prevOpenedRef.current = opened; + }, [opened, searchModels, reset]); + + useEffect(() => { + if (opened && debouncedQuery !== undefined) { + searchModels(debouncedQuery); + } + }, [debouncedQuery, opened, searchModels]); + + const handleClose = () => { + setSearchQuery(initialSearchParams.search || ''); + onClose(); + }; + + const handleModelSelect = (model: HuggingFaceModelInfo) => { + loadModelFiles(model); + }; + + const handleFileSelect = (file: HuggingFaceFileInfo) => { + if (!selectedModel) return; + const url = getFileDownloadUrl(selectedModel.id, file.path); + onSelect(url); + handleClose(); + }; + + const handleBack = () => { + reset(); + searchModels(searchQuery); + }; + + const handleOpenExternal = () => { + if (selectedModel) { + window.electronAPI.app.openExternal( + `${HUGGINGFACE_BASE_URL}/${selectedModel.id}` + ); + } + }; + + const getFilterBadges = () => { + const badges: string[] = []; + if (searchParams?.filter) badges.push(searchParams.filter.toUpperCase()); + if (searchParams?.pipelineTag) + badges.push(searchParams.pipelineTag.replace('-', ' ')); + return badges; + }; + + return ( + + + {selectedModel ? ( + + + + + + + {selectedModel.name} + + + {selectedModel.author} + + + + + + + + + ) : ( + + } + value={searchQuery} + onChange={(e) => setSearchQuery(e.currentTarget.value)} + rightSection={loading ? : null} + /> + + + + {getFilterBadges().map((badge) => ( + + {badge} + + ))} + + + + )} + + {error && ( + + {error} + + )} + + { + const target = scrollAreaRef.current; + if (!target) return; + const isNearBottom = + target.scrollHeight - y <= target.clientHeight + 100; + if (isNearBottom && hasMore && !loading && !selectedModel) { + loadMoreModels(); + } + }} + viewportRef={scrollAreaRef} + > + {selectedModel ? ( + + + + + ) : ( + changeSortOrder(sort, searchQuery)} + /> + )} + + + {loading && !selectedModel && models.length > 0 && ( + + + + Loading more... + + + )} + + + ); +}; diff --git a/src/components/screens/Launch/ImageGenerationTab.tsx b/src/components/screens/Launch/ImageGenerationTab.tsx index 11c808e..98228ca 100644 --- a/src/components/screens/Launch/ImageGenerationTab.tsx +++ b/src/components/screens/Launch/ImageGenerationTab.tsx @@ -69,7 +69,11 @@ export const ImageGenerationTab = () => { tooltip="The primary image generation model. This is the main model that will generate images." onChange={setSdmodel} onSelectFile={() => selectFile('sdmodel', 'Select Image Model')} - searchUrl="https://huggingface.co/models?pipeline_tag=text-to-image&library=gguf&sort=trending" + searchParams={{ + pipelineTag: 'text-to-image', + filter: 'gguf', + sort: 'trendingScore', + }} showAnalyze paramType="sdmodel" /> @@ -81,7 +85,11 @@ export const ImageGenerationTab = () => { tooltip="T5-XXL text encoder model for advanced text understanding." onChange={setSdt5xxl} onSelectFile={() => selectFile('sdt5xxl', 'Select T5XXL Model')} - searchUrl="https://huggingface.co/models?search=t5-xxl&library=gguf&sort=trending" + searchParams={{ + search: 't5xxl', + filter: 'safetensors', + sort: 'trendingScore', + }} paramType="sdt5xxl" /> @@ -92,7 +100,11 @@ export const ImageGenerationTab = () => { tooltip="CLIP-L text encoder model for text-image understanding." onChange={setSdclipl} onSelectFile={() => selectFile('sdclipl', 'Select CLIP-L Model')} - searchUrl="https://huggingface.co/models?search=clip-l&library=gguf&sort=trending" + searchParams={{ + search: 'clip', + filter: 'safetensors', + sort: 'trendingScore', + }} paramType="sdclipl" /> @@ -100,10 +112,14 @@ export const ImageGenerationTab = () => { label="Clip-G File" value={sdclipg} placeholder="Select a Clip-G file or enter a direct URL" - tooltip="CLIP-G text encoder model for enhanced text-image understanding." + tooltip="CLIP-G text encoder model for enhanced text-image understanding, or mmproj files for vision-language models." onChange={setSdclipg} onSelectFile={() => selectFile('sdclipg', 'Select CLIP-G Model')} - searchUrl="https://huggingface.co/models?search=clip-g&library=gguf&sort=trending" + searchParams={{ + search: 'clip', + filter: 'gguf', + sort: 'trendingScore', + }} paramType="sdclipg" /> @@ -116,7 +132,11 @@ export const ImageGenerationTab = () => { onSelectFile={() => selectFile('sdphotomaker', 'Select PhotoMaker Model') } - searchUrl="https://huggingface.co/models?search=photomaker&library=safetensors&sort=trending" + searchParams={{ + search: 'photomaker', + filter: 'safetensors', + sort: 'trendingScore', + }} paramType="sdphotomaker" /> @@ -127,7 +147,11 @@ export const ImageGenerationTab = () => { tooltip="Variational Autoencoder model for improved image quality." onChange={setSdvae} onSelectFile={() => selectFile('sdvae', 'Select VAE Model')} - searchUrl="https://huggingface.co/models?search=vae&library=safetensors&sort=trending" + searchParams={{ + search: 'vae', + filter: 'safetensors', + sort: 'trendingScore', + }} paramType="sdvae" /> @@ -138,7 +162,11 @@ export const ImageGenerationTab = () => { tooltip="LoRa (Low-Rank Adaptation) file for customizing image generation. Select a .safetensors or .gguf LoRa file to be loaded. Should be unquantized." onChange={setSdlora} onSelectFile={() => selectFile('sdlora', 'Select LoRA Model')} - searchUrl="https://huggingface.co/models?search=lora&library=safetensors&sort=trending" + searchParams={{ + search: 'lora', + filter: 'safetensors', + sort: 'trendingScore', + }} paramType="sdlora" /> diff --git a/src/components/screens/Launch/ModelFileField.tsx b/src/components/screens/Launch/ModelFileField.tsx index 8ee92e0..c33d32a 100644 --- a/src/components/screens/Launch/ModelFileField.tsx +++ b/src/components/screens/Launch/ModelFileField.tsx @@ -11,9 +11,15 @@ import { import { File, Search, Info } from 'lucide-react'; import { LabelWithTooltip } from '@/components/LabelWithTooltip'; import { ModelAnalysisModal } from '@/components/screens/Launch/ModelAnalysisModal'; +import { HuggingFaceSearchModal } from '@/components/screens/Launch/HuggingFaceSearchModal'; import { getInputValidationState } from '@/utils/validation'; import { logError } from '@/utils/logger'; -import type { ModelAnalysis, ModelParamType, CachedModel } from '@/types'; +import type { + ModelAnalysis, + ModelParamType, + CachedModel, + HuggingFaceSearchParams, +} from '@/types'; interface ModelFileFieldProps { label: string; @@ -22,7 +28,7 @@ interface ModelFileFieldProps { tooltip?: string; onChange: (value: string) => void; onSelectFile: () => void; - searchUrl?: string; + searchParams?: HuggingFaceSearchParams; showAnalyze?: boolean; paramType: ModelParamType; } @@ -34,7 +40,7 @@ export const ModelFileField = ({ tooltip, onChange, onSelectFile, - searchUrl, + searchParams, showAnalyze = false, paramType, }: ModelFileFieldProps) => { @@ -46,6 +52,7 @@ export const ModelFileField = ({ const [analysisLoading, setAnalysisLoading] = useState(false); const [analysisError, setAnalysisError] = useState(); const [cachedModels, setCachedModels] = useState([]); + const [searchModalOpened, setSearchModalOpened] = useState(false); const combobox = useCombobox(); useEffect(() => { @@ -141,10 +148,10 @@ export const ModelFileField = ({ > Browse - {searchUrl && ( + {searchParams && ( window.electronAPI.app.openExternal(searchUrl)} + onClick={() => setSearchModalOpened(true)} variant="outline" size="lg" > @@ -182,6 +189,15 @@ export const ModelFileField = ({ loading={analysisLoading} error={analysisError} /> + + {searchParams && ( + setSearchModalOpened(false)} + onSelect={onChange} + searchParams={searchParams} + /> + )} ); }; diff --git a/src/components/settings/SettingsModal.tsx b/src/components/settings/SettingsModal.tsx index 234a9d4..674eb0f 100644 --- a/src/components/settings/SettingsModal.tsx +++ b/src/components/settings/SettingsModal.tsx @@ -67,118 +67,105 @@ export const SettingsModal = ({ } size="xl" showCloseButton + tallContent > -
value && setActiveTab(value)} + orientation="vertical" + variant="pills" + styles={{ + root: { + flex: 1, + minHeight: 0, + }, + panel: { + height: '100%', + overflow: 'auto', + paddingLeft: '1.5rem', + paddingRight: '1.5rem', + }, + tabLabel: { + textAlign: 'left', + justifyContent: 'flex-start', + }, }} > - value && setActiveTab(value)} - orientation="vertical" - variant="pills" - styles={{ - root: { - flex: 1, - minHeight: 0, - }, - panel: { - height: '100%', - overflow: 'auto', - paddingLeft: '1.5rem', - paddingRight: '1.5rem', - }, - tabLabel: { - textAlign: 'left', - justifyContent: 'flex-start', - }, - }} - > - - - } - > - General - - {showBackendsTab && ( - - } - > - Backends - - )} - - } - > - Appearance - - - } - > - System - - - } - > - Troubleshooting - - } - > - About - - - - - - - + + + } + > + General + {showBackendsTab && ( - - - + + } + > + Backends + )} + + } + > + Appearance + + + } + > + System + + } + > + Troubleshooting + + } + > + About + + - - - + + + - - + {showBackendsTab && ( + + + )} - - - + + + - - - - -
+ + + + + + + + + + + + ); }; diff --git a/src/constants/imageModelPresets.ts b/src/constants/imageModelPresets.ts index 7380da0..e9c7896 100644 --- a/src/constants/imageModelPresets.ts +++ b/src/constants/imageModelPresets.ts @@ -1,3 +1,5 @@ +import { HUGGINGFACE_BASE_URL } from '@/constants'; + export interface ImageModelPreset { readonly name: string; readonly sdmodel: string; @@ -11,53 +13,38 @@ export interface ImageModelPreset { export const IMAGE_MODEL_PRESETS: readonly ImageModelPreset[] = [ { name: 'Z-Image', - sdmodel: - 'https://huggingface.co/leejet/Z-Image-Turbo-GGUF/resolve/main/z_image_turbo-Q4_0.gguf', + sdmodel: `${HUGGINGFACE_BASE_URL}/leejet/Z-Image-Turbo-GGUF/resolve/main/z_image_turbo-Q4_0.gguf`, sdt5xxl: '', - sdclipl: - 'https://huggingface.co/unsloth/Qwen3-4B-Instruct-2507-GGUF/resolve/main/Qwen3-4B-Instruct-2507-Q4_K_S.gguf', + sdclipl: `${HUGGINGFACE_BASE_URL}/unsloth/Qwen3-4B-Instruct-2507-GGUF/resolve/main/Qwen3-4B-Instruct-2507-Q4_K_S.gguf`, sdclipg: '', sdphotomaker: '', - sdvae: - 'https://huggingface.co/koboldcpp/GGUFDumps/resolve/main/flux1vae.safetensors', + sdvae: `${HUGGINGFACE_BASE_URL}/koboldcpp/GGUFDumps/resolve/main/flux1vae.safetensors`, }, { name: 'FLUX.1', - sdmodel: - 'https://huggingface.co/bullerwins/FLUX.1-Kontext-dev-GGUF/resolve/main/flux1-kontext-dev-Q4_K_S.gguf', - sdt5xxl: - 'https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/t5xxl_fp8_e4m3fn.safetensors', - sdclipl: - 'https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/clip_l.safetensors', + sdmodel: `${HUGGINGFACE_BASE_URL}/bullerwins/FLUX.1-Kontext-dev-GGUF/resolve/main/flux1-kontext-dev-Q4_K_S.gguf`, + sdt5xxl: `${HUGGINGFACE_BASE_URL}/camenduru/FLUX.1-dev/resolve/main/t5xxl_fp8_e4m3fn.safetensors`, + sdclipl: `${HUGGINGFACE_BASE_URL}/camenduru/FLUX.1-dev/resolve/main/clip_l.safetensors`, sdclipg: '', sdphotomaker: '', - sdvae: - 'https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/ae.safetensors', + sdvae: `${HUGGINGFACE_BASE_URL}/camenduru/FLUX.1-dev/resolve/main/ae.safetensors`, }, { name: 'Chroma', - sdmodel: - 'https://huggingface.co/silveroxides/Chroma-GGUF/resolve/main/chroma-unlocked-v45/chroma-unlocked-v45-Q4_0.gguf', - sdt5xxl: - 'https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/t5xxl_fp8_e4m3fn.safetensors', - sdclipl: - 'https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/clip_l.safetensors', + sdmodel: `${HUGGINGFACE_BASE_URL}/silveroxides/Chroma-GGUF/resolve/main/chroma-unlocked-v45/chroma-unlocked-v45-Q4_0.gguf`, + sdt5xxl: `${HUGGINGFACE_BASE_URL}/camenduru/FLUX.1-dev/resolve/main/t5xxl_fp8_e4m3fn.safetensors`, + sdclipl: `${HUGGINGFACE_BASE_URL}/camenduru/FLUX.1-dev/resolve/main/clip_l.safetensors`, sdclipg: '', sdphotomaker: '', - sdvae: - 'https://huggingface.co/lodestones/Chroma/resolve/main/ae.safetensors', + sdvae: `${HUGGINGFACE_BASE_URL}/lodestones/Chroma/resolve/main/ae.safetensors`, }, { name: 'Qwen Image Edit 2509', - sdmodel: - 'https://huggingface.co/QuantStack/Qwen-Image-Edit-2509-GGUF/resolve/main/Qwen-Image-Edit-2509-Q4_K_S.gguf', + sdmodel: `${HUGGINGFACE_BASE_URL}/QuantStack/Qwen-Image-Edit-2509-GGUF/resolve/main/Qwen-Image-Edit-2509-Q4_K_S.gguf`, sdt5xxl: '', - sdclipl: - 'https://huggingface.co/mradermacher/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct.Q4_K_S.gguf', - sdclipg: - 'https://huggingface.co/mradermacher/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct.mmproj-Q8_0.gguf', + sdclipl: `${HUGGINGFACE_BASE_URL}/mradermacher/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct.Q4_K_S.gguf`, + sdclipg: `${HUGGINGFACE_BASE_URL}/mradermacher/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct.mmproj-Q8_0.gguf`, sdphotomaker: '', - sdvae: - 'https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors', + sdvae: `${HUGGINGFACE_BASE_URL}/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors`, }, ] as const; diff --git a/src/constants/index.ts b/src/constants/index.ts index 9b1b186..a6bb42a 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -6,6 +6,8 @@ export const TITLEBAR_HEIGHT = '2.5rem'; export const STATUSBAR_HEIGHT = '1.5rem'; +export const HUGGINGFACE_BASE_URL = 'https://huggingface.co'; + export const SERVER_READY_SIGNALS = { KOBOLDCPP: 'Please connect to custom endpoint at', SILLYTAVERN: 'SillyTavern is listening on', @@ -14,8 +16,7 @@ export const SERVER_READY_SIGNALS = { export const DEFAULT_CONTEXT_SIZE = 4096; -export const DEFAULT_MODEL_URL = - 'https://huggingface.co/MaziyarPanahi/gemma-3-4b-it-GGUF/resolve/main/gemma-3-4b-it.Q8_0.gguf'; +export const DEFAULT_MODEL_URL = `${HUGGINGFACE_BASE_URL}/MaziyarPanahi/gemma-3-4b-it-GGUF/resolve/main/gemma-3-4b-it.Q8_0.gguf`; export const DEFAULT_AUTO_GPU_LAYERS = true; diff --git a/src/hooks/useHuggingFaceSearch.ts b/src/hooks/useHuggingFaceSearch.ts new file mode 100644 index 0000000..5e5af62 --- /dev/null +++ b/src/hooks/useHuggingFaceSearch.ts @@ -0,0 +1,356 @@ +import { useState, useCallback, useRef } from 'react'; +import { logError } from '@/utils/logger'; +import type { + HuggingFaceModelInfo, + HuggingFaceFileInfo, + HuggingFaceSearchParams, + HuggingFaceSortOption, +} from '@/types'; + +import { HUGGINGFACE_BASE_URL } from '@/constants'; + +const MODELS_PER_PAGE = 20; +const HF_API_BASE = `${HUGGINGFACE_BASE_URL}/api`; + +interface HFApiModel { + id: string; + downloads: number; + likes: number; + lastModified: string; + gated: boolean | 'auto' | 'manual'; + tags: string[]; +} + +interface HFApiFile { + type: 'file' | 'directory'; + path: string; + size: number; + lfs?: { + size: number; + }; +} + +interface HFApiBaseModel { + safetensors?: { + parameters?: { + BF16?: number; + F32?: number; + total?: number; + }; + total?: number; + }; +} + +const isValidModelId = (id: string) => id.includes('/'); + +const extractParamSize = (name: string) => { + const match = name.match(/(\d+(?:\.\d+)?[BM])(?!\d)/i); + return match ? match[1].toUpperCase() : undefined; +}; + +const extractBaseModelId = (tags: string[]) => { + const baseModelTag = tags.find( + (tag) => tag.startsWith('base_model:') && !tag.includes('quantized') + ); + return baseModelTag?.replace('base_model:', ''); +}; + +const formatParamCount = (paramCount: number) => { + if (paramCount >= 1_000_000_000) { + const billions = paramCount / 1_000_000_000; + return billions % 1 === 0 ? `${billions}B` : `${billions.toFixed(1)}B`; + } + if (paramCount >= 1_000_000) { + const millions = paramCount / 1_000_000; + return millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`; + } + return `${paramCount}`; +}; + +const fetchBaseModelParams = async (baseModelId: string) => { + try { + const response = await fetch(`${HF_API_BASE}/models/${baseModelId}`); + if (!response.ok) return undefined; + const data: HFApiBaseModel = await response.json(); + return data.safetensors?.total; + } catch { + return undefined; + } +}; + +export const useHuggingFaceSearch = ( + initialParams: HuggingFaceSearchParams +) => { + const [models, setModels] = useState([]); + const [files, setFiles] = useState([]); + const [loading, setLoading] = useState(false); + const [loadingFiles, setLoadingFiles] = useState(false); + const [error, setError] = useState(); + const [hasMore, setHasMore] = useState(true); + const [selectedModel, setSelectedModel] = useState(); + const [sortBy, setSortBy] = useState( + initialParams.sort + ); + const [searchParams] = useState(initialParams); + const pageRef = useRef(0); + const currentQueryRef = useRef(undefined); + + const searchModels = useCallback( + async ( + query?: string, + reset = true, + sort: HuggingFaceSortOption = sortBy + ) => { + if (reset) { + setModels([]); + setHasMore(true); + setError(undefined); + setSelectedModel(undefined); + setFiles([]); + pageRef.current = 0; + } + + setLoading(true); + setSortBy(sort); + currentQueryRef.current = query; + + try { + const searchQuery = + query !== undefined ? query.trim() || undefined : searchParams.search; + + const params = new URLSearchParams(); + if (searchQuery) params.set('search', searchQuery); + if (searchParams.pipelineTag) + params.set('pipeline_tag', searchParams.pipelineTag); + if (searchParams.filter) params.set('filter', searchParams.filter); + params.set('sort', sort); + params.set('limit', String(MODELS_PER_PAGE)); + params.set('full', 'false'); + + const response = await fetch( + `${HF_API_BASE}/models?${params.toString()}` + ); + + if (!response.ok) { + throw new Error(`Failed to fetch models: ${response.statusText}`); + } + + const data: HFApiModel[] = await response.json(); + const validModels = data.filter((model) => isValidModelId(model.id)); + + const results = await Promise.all( + validModels.map(async (model) => { + const [author, ...nameParts] = model.id.split('/'); + const name = nameParts.join('/'); + let paramSize = extractParamSize(name); + + if (!paramSize) { + const baseModelId = extractBaseModelId(model.tags); + if (baseModelId) { + const paramCount = await fetchBaseModelParams(baseModelId); + if (paramCount) { + paramSize = formatParamCount(paramCount); + } + } + } + + return { + id: model.id, + name, + author, + downloads: model.downloads ?? 0, + likes: model.likes ?? 0, + updatedAt: new Date(model.lastModified), + gated: model.gated ?? false, + paramSize, + }; + }) + ); + + setModels(results); + setHasMore(data.length === MODELS_PER_PAGE); + pageRef.current = 1; + } catch (err) { + const message = + err instanceof Error ? err.message : 'Failed to search models'; + setError(message); + logError('HuggingFace search failed:', err as Error); + } finally { + setLoading(false); + } + }, + [searchParams, sortBy] + ); + + const changeSortOrder = useCallback( + (sort: HuggingFaceSortOption, query?: string) => { + searchModels(query, true, sort); + }, + [searchModels] + ); + + const loadMoreModels = useCallback(async () => { + if (loading || !hasMore) return; + + setLoading(true); + + try { + const searchQuery = + currentQueryRef.current !== undefined + ? currentQueryRef.current.trim() || undefined + : searchParams.search; + + const params = new URLSearchParams(); + if (searchQuery) params.set('search', searchQuery); + if (searchParams.pipelineTag) + params.set('pipeline_tag', searchParams.pipelineTag); + if (searchParams.filter) params.set('filter', searchParams.filter); + params.set('sort', sortBy); + params.set('limit', String(MODELS_PER_PAGE)); + params.set('skip', String(pageRef.current * MODELS_PER_PAGE)); + params.set('full', 'false'); + + const response = await fetch( + `${HF_API_BASE}/models?${params.toString()}` + ); + if (!response.ok) { + throw new Error(`Failed to fetch models: ${response.statusText}`); + } + + const data: HFApiModel[] = await response.json(); + const validModels = data.filter((model) => isValidModelId(model.id)); + + const results = await Promise.all( + validModels.map(async (model) => { + const [author, ...nameParts] = model.id.split('/'); + const name = nameParts.join('/'); + let paramSize = extractParamSize(name); + + if (!paramSize) { + const baseModelId = extractBaseModelId(model.tags); + if (baseModelId) { + const paramCount = await fetchBaseModelParams(baseModelId); + if (paramCount) { + paramSize = formatParamCount(paramCount); + } + } + } + + return { + id: model.id, + name, + author, + downloads: model.downloads ?? 0, + likes: model.likes ?? 0, + updatedAt: new Date(model.lastModified), + gated: model.gated ?? false, + paramSize, + }; + }) + ); + + setModels((prev) => [...prev, ...results]); + setHasMore(validModels.length === MODELS_PER_PAGE); + pageRef.current += 1; + } catch (err) { + const message = + err instanceof Error ? err.message : 'Failed to load more models'; + setError(message); + logError('HuggingFace load more failed:', err as Error); + } finally { + setLoading(false); + } + }, [loading, hasMore, searchParams, sortBy]); + + const loadModelFiles = useCallback( + async (model: HuggingFaceModelInfo) => { + setSelectedModel(model); + setFiles([]); + setLoadingFiles(true); + setError(undefined); + + try { + const filter = searchParams?.filter; + const extensions = getExtensionsForLibrary(filter); + + const response = await fetch( + `${HF_API_BASE}/models/${model.id}/tree/main?recursive=true` + ); + + if (!response.ok) { + throw new Error(`Failed to fetch files: ${response.statusText}`); + } + + const items: HFApiFile[] = await response.json(); + const fileResults: HuggingFaceFileInfo[] = []; + + for (const file of items) { + if ( + file.type === 'file' && + extensions.some((ext) => file.path.endsWith(ext)) + ) { + fileResults.push({ + path: file.path, + size: file.lfs?.size ?? file.size, + }); + } + } + + fileResults.sort((a, b) => b.size - a.size); + setFiles(fileResults); + } catch (err) { + const message = + err instanceof Error ? err.message : 'Failed to load model files'; + setError(message); + logError('HuggingFace list files failed:', err as Error); + } finally { + setLoadingFiles(false); + } + }, + [searchParams?.filter] + ); + + const getFileDownloadUrl = useCallback( + (modelId: string, filePath: string) => + `${HUGGINGFACE_BASE_URL}/${modelId}/resolve/main/${filePath}`, + [] + ); + + const reset = useCallback(() => { + setModels([]); + setFiles([]); + setSelectedModel(undefined); + setError(undefined); + setHasMore(true); + pageRef.current = 0; + }, []); + + return { + models, + files, + loading, + loadingFiles, + error, + hasMore, + selectedModel, + sortBy, + searchParams, + searchModels, + loadMoreModels, + loadModelFiles, + changeSortOrder, + getFileDownloadUrl, + reset, + }; +}; + +const getExtensionsForLibrary = (filter?: string) => { + switch (filter) { + case 'gguf': + return ['.gguf']; + case 'safetensors': + return ['.safetensors']; + default: + return ['.gguf', '.safetensors', '.bin', '.pt', '.pth']; + } +}; diff --git a/src/main/modules/koboldcpp/config.ts b/src/main/modules/koboldcpp/config.ts index 6d04cfe..ae5e756 100644 --- a/src/main/modules/koboldcpp/config.ts +++ b/src/main/modules/koboldcpp/config.ts @@ -3,7 +3,7 @@ import { readdir, stat, unlink } from 'fs/promises'; import { dialog } from 'electron'; import { getInstallDir, setInstallDir } from '../config'; -import { logError } from '@/utils/node/logging'; +import { logError, safeExecute, tryExecute } from '@/utils/node/logging'; import { pathExists, readJsonFile, writeJsonFile } from '@/utils/node/fs'; import { getMainWindow, sendToRenderer } from '../window'; import { PRODUCT_NAME } from '@/constants'; @@ -43,48 +43,37 @@ export async function getConfigFiles() { } export async function parseConfigFile(filePath: string) { - try { + return safeExecute(async () => { if (!(await pathExists(filePath))) { return null; } const config = await readJsonFile(filePath); return config as KoboldConfig; - } catch (error) { - logError('Error parsing config file:', error as Error); - return null; - } + }, 'Error parsing config file'); } export async function saveConfigFile( configFileName: string, configData: KoboldConfig ) { - try { + return tryExecute(async () => { const installDir = getInstallDir(); const configPath = join(installDir, configFileName); await writeJsonFile(configPath, configData); - return true; - } catch (error) { - logError('Error saving config file:', error as Error); - return false; - } + }, 'Error saving config file'); } export async function deleteConfigFile(configFileName: string) { - try { + return tryExecute(async () => { const installDir = getInstallDir(); const configPath = join(installDir, configFileName); await unlink(configPath); - return true; - } catch (error) { - logError('Error deleting config file:', error as Error); - return false; - } + }, 'Error deleting config file'); } export async function selectModelFile(title = 'Select Model File') { - try { + return safeExecute(async () => { const mainWindow = getMainWindow(); if (!mainWindow) { return null; @@ -107,10 +96,7 @@ export async function selectModelFile(title = 'Select Model File') { } return result.filePaths[0]; - } catch (error) { - logError('Error selecting model file:', error as Error); - return null; - } + }, 'Error selecting model file'); } export async function selectInstallDirectory() { diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 133e76b..166ebdf 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -125,3 +125,32 @@ export interface ModelAnalysis { vramPerLayer?: string; }; } + +export interface HuggingFaceModelInfo { + id: string; + name: string; + author: string; + downloads: number; + likes: number; + updatedAt: Date; + gated: boolean | 'auto' | 'manual'; + paramSize?: string; +} + +export interface HuggingFaceFileInfo { + path: string; + size: number; +} + +export interface HuggingFaceSearchParams { + search?: string; + pipelineTag?: string; + filter?: string; + sort: HuggingFaceSortOption; +} + +export type HuggingFaceSortOption = + | 'trendingScore' + | 'downloads' + | 'likes' + | 'lastModified'; diff --git a/src/utils/format.ts b/src/utils/format.ts index 009fa60..ace2361 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -48,3 +48,22 @@ export const formatDeviceName = (deviceName: string) => export const stripFileExtension = (filename: string) => filename.replace(/\.[^/.]+$/, ''); + +export const formatDownloads = (count: number) => { + if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M`; + if (count >= 1_000) return `${(count / 1_000).toFixed(1)}K`; + return count.toString(); +}; + +export const formatDate = (date: Date) => { + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + + if (days === 0) return 'today'; + if (days === 1) return 'yesterday'; + if (days < 7) return `${days}d ago`; + if (days < 30) return `${Math.floor(days / 7)}w ago`; + if (days < 365) return `${Math.floor(days / 30)}mo ago`; + return `${Math.floor(days / 365)}y ago`; +}; diff --git a/yarn.lock b/yarn.lock index 97e5691..e0cf3a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1305,7 +1305,7 @@ __metadata: languageName: node linkType: hard -"@types/debug@npm:^4.1.6": +"@types/debug@npm:^4.0.0, @types/debug@npm:^4.1.6": version: 4.1.12 resolution: "@types/debug@npm:4.1.12" dependencies: @@ -1314,7 +1314,16 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.6": +"@types/estree-jsx@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree-jsx@npm:1.0.5" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/07b354331516428b27a3ab99ee397547d47eb223c34053b48f84872fafb841770834b90cc1a0068398e7c7ccb15ec51ab00ec64b31dc5e3dbefd624638a35c6d + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 @@ -1330,6 +1339,15 @@ __metadata: languageName: node linkType: hard +"@types/hast@npm:^3.0.0": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + languageName: node + linkType: hard + "@types/http-cache-semantics@npm:*": version: 4.0.4 resolution: "@types/http-cache-semantics@npm:4.0.4" @@ -1360,6 +1378,15 @@ __metadata: languageName: node linkType: hard +"@types/mdast@npm:^4.0.0": + version: 4.0.4 + resolution: "@types/mdast@npm:4.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/84f403dbe582ee508fd9c7643ac781ad8597fcbfc9ccb8d4715a2c92e4545e5772cbd0dbdf18eda65789386d81b009967fdef01b24faf6640f817287f54d9c82 + languageName: node + linkType: hard + "@types/mime-types@npm:^3.0.1": version: 3.0.1 resolution: "@types/mime-types@npm:3.0.1" @@ -1436,6 +1463,20 @@ __metadata: languageName: node linkType: hard +"@types/unist@npm:*, @types/unist@npm:^3.0.0": + version: 3.0.3 + resolution: "@types/unist@npm:3.0.3" + checksum: 10c0/2b1e4adcab78388e088fcc3c0ae8700f76619dbcb4741d7d201f87e2cb346bfc29a89003cfea2d76c996e1061452e14fcd737e8b25aacf949c1f2d6b2bc3dd60 + languageName: node + linkType: hard + +"@types/unist@npm:^2.0.0": + version: 2.0.11 + resolution: "@types/unist@npm:2.0.11" + checksum: 10c0/24dcdf25a168f453bb70298145eb043cfdbb82472db0bc0b56d6d51cd2e484b9ed8271d4ac93000a80da568f2402e9339723db262d0869e2bf13bc58e081768d + languageName: node + linkType: hard + "@types/verror@npm:^1.10.3": version: 1.10.11 resolution: "@types/verror@npm:1.10.11" @@ -1633,6 +1674,13 @@ __metadata: languageName: node linkType: hard +"@ungap/structured-clone@npm:^1.0.0": + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 10c0/0fc3097c2540ada1fc340ee56d58d96b5b536a2a0dab6e3ec17d4bfc8c4c86db345f61a375a8185f9da96f01c69678f836a2b57eeaa9e4b8eeafd26428e57b0a + languageName: node + linkType: hard + "@vitejs/plugin-react@npm:^5.1.1": version: 5.1.1 resolution: "@vitejs/plugin-react@npm:5.1.1" @@ -1970,6 +2018,13 @@ __metadata: languageName: node linkType: hard +"bail@npm:^2.0.0": + version: 2.0.2 + resolution: "bail@npm:2.0.2" + checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -2213,6 +2268,13 @@ __metadata: languageName: node linkType: hard +"ccount@npm:^2.0.0": + version: 2.0.1 + resolution: "ccount@npm:2.0.1" + checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350 + languageName: node + linkType: hard + "chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -2223,6 +2285,34 @@ __metadata: languageName: node linkType: hard +"character-entities-html4@npm:^2.0.0": + version: 2.1.0 + resolution: "character-entities-html4@npm:2.1.0" + checksum: 10c0/fe61b553f083400c20c0b0fd65095df30a0b445d960f3bbf271536ae6c3ba676f39cb7af0b4bf2755812f08ab9b88f2feed68f9aebb73bb153f7a115fe5c6e40 + languageName: node + linkType: hard + +"character-entities-legacy@npm:^3.0.0": + version: 3.0.0 + resolution: "character-entities-legacy@npm:3.0.0" + checksum: 10c0/ec4b430af873661aa754a896a2b55af089b4e938d3d010fad5219299a6b6d32ab175142699ee250640678cd64bdecd6db3c9af0b8759ab7b155d970d84c4c7d1 + languageName: node + linkType: hard + +"character-entities@npm:^2.0.0": + version: 2.0.2 + resolution: "character-entities@npm:2.0.2" + checksum: 10c0/b0c645a45bcc90ff24f0e0140f4875a8436b8ef13b6bcd31ec02cfb2ca502b680362aa95386f7815bdc04b6464d48cf191210b3840d7c04241a149ede591a308 + languageName: node + linkType: hard + +"character-reference-invalid@npm:^2.0.0": + version: 2.0.1 + resolution: "character-reference-invalid@npm:2.0.1" + checksum: 10c0/2ae0dec770cd8659d7e8b0ce24392d83b4c2f0eb4a3395c955dce5528edd4cc030a794cfa06600fcdd700b3f2de2f9b8e40e309c0011c4180e3be64a0b42e6a1 + languageName: node + linkType: hard + "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" @@ -2386,6 +2476,13 @@ __metadata: languageName: node linkType: hard +"comma-separated-tokens@npm:^2.0.0": + version: 2.0.3 + resolution: "comma-separated-tokens@npm:2.0.3" + checksum: 10c0/91f90f1aae320f1755d6957ef0b864fe4f54737f3313bd95e0802686ee2ca38bff1dd381964d00ae5db42912dd1f4ae5c2709644e82706ffc6f6842a813cdd67 + languageName: node + linkType: hard + "commander@npm:^5.0.0": version: 5.1.0 resolution: "commander@npm:5.1.0" @@ -2501,7 +2598,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -2522,6 +2619,15 @@ __metadata: languageName: node linkType: hard +"decode-named-character-reference@npm:^1.0.0": + version: 1.2.0 + resolution: "decode-named-character-reference@npm:1.2.0" + dependencies: + character-entities: "npm:^2.0.0" + checksum: 10c0/761a89de6b0e0a2d4b21ae99074e4cc3344dd11eb29f112e23cc5909f2e9f33c5ed20cd6b146b27fb78170bce0f3f9b3362a84b75638676a05c938c24a60f5d7 + languageName: node + linkType: hard + "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -2590,6 +2696,13 @@ __metadata: languageName: node linkType: hard +"dequal@npm:^2.0.0": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + "detect-libc@npm:^2.0.1": version: 2.1.2 resolution: "detect-libc@npm:2.1.2" @@ -2611,6 +2724,15 @@ __metadata: languageName: node linkType: hard +"devlop@npm:^1.0.0, devlop@npm:^1.1.0": + version: 1.1.0 + resolution: "devlop@npm:1.1.0" + dependencies: + dequal: "npm:^2.0.0" + checksum: 10c0/e0928ab8f94c59417a2b8389c45c55ce0a02d9ac7fd74ef62d01ba48060129e1d594501b77de01f3eeafc7cb00773819b0df74d96251cf20b31c5b3071f45c0e + languageName: node + linkType: hard + "dir-compare@npm:^4.2.0": version: 4.2.0 resolution: "dir-compare@npm:4.2.0" @@ -2844,6 +2966,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 10c0/ed836ddac5acb34341094eb495185d527bd70e8632b6c0d59548cbfa23defdbae70b96f9a405c82904efa421230b5b3fd2283752447d737beffd3f3e6ee74414 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -3109,6 +3238,13 @@ __metadata: languageName: node linkType: hard +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 10c0/6366f474c6f37a802800a435232395e04e9885919873e382b157ab7e8f0feb8fed71497f84a6f6a81a49aab41815522f5839112bd38026d203aea0c91622df95 + languageName: node + linkType: hard + "eslint-import-resolver-node@npm:^0.3.9": version: 0.3.9 resolution: "eslint-import-resolver-node@npm:0.3.9" @@ -3351,6 +3487,13 @@ __metadata: languageName: node linkType: hard +"estree-util-is-identifier-name@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-is-identifier-name@npm:3.0.0" + checksum: 10c0/d1881c6ed14bd588ebd508fc90bf2a541811dbb9ca04dec2f39d27dcaa635f85b5ed9bbbe7fc6fb1ddfca68744a5f7c70456b4b7108b6c4c52780631cc787c5b + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -3385,6 +3528,13 @@ __metadata: languageName: node linkType: hard +"extend@npm:^3.0.0": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 + languageName: node + linkType: hard + "extract-zip@npm:^2.0.1": version: 2.0.1 resolution: "extract-zip@npm:2.0.1" @@ -3740,10 +3890,14 @@ __metadata: react: "npm:^19.2.1" react-dom: "npm:^19.2.1" react-error-boundary: "npm:^6.0.0" + react-markdown: "npm:^10.1.0" + rehype-raw: "npm:^7.0.0" + rehype-sanitize: "npm:^6.0.0" + remark-gfm: "npm:^4.0.1" rollup-plugin-visualizer: "npm:^6.0.5" systeminformation: "npm:^5.27.11" typescript: "npm:^5.9.3" - vite: "npm:^7.2.6" + vite: "npm:^7.2.7" winston: "npm:^3.19.0" winston-daily-rotate-file: "npm:^5.0.0" yauzl: "npm:^3.2.0" @@ -4000,6 +4154,123 @@ __metadata: languageName: node linkType: hard +"hast-util-from-parse5@npm:^8.0.0": + version: 8.0.3 + resolution: "hast-util-from-parse5@npm:8.0.3" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + devlop: "npm:^1.0.0" + hastscript: "npm:^9.0.0" + property-information: "npm:^7.0.0" + vfile: "npm:^6.0.0" + vfile-location: "npm:^5.0.0" + web-namespaces: "npm:^2.0.0" + checksum: 10c0/40ace6c0ad43c26f721c7499fe408e639cde917b2350c9299635e6326559855896dae3c3ebf7440df54766b96c4276a7823e8f376a2b6a28b37b591f03412545 + languageName: node + linkType: hard + +"hast-util-parse-selector@npm:^4.0.0": + version: 4.0.0 + resolution: "hast-util-parse-selector@npm:4.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/5e98168cb44470dc274aabf1a28317e4feb09b1eaf7a48bbaa8c1de1b43a89cd195cb1284e535698e658e3ec26ad91bc5e52c9563c36feb75abbc68aaf68fb9f + languageName: node + linkType: hard + +"hast-util-raw@npm:^9.0.0": + version: 9.1.0 + resolution: "hast-util-raw@npm:9.1.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + hast-util-from-parse5: "npm:^8.0.0" + hast-util-to-parse5: "npm:^8.0.0" + html-void-elements: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + parse5: "npm:^7.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/d0d909d2aedecef6a06f0005cfae410d6475e6e182d768bde30c3af9fcbbe4f9beb0522bdc21d0679cb3c243c0df40385797ed255148d68b3d3f12e82d12aacc + languageName: node + linkType: hard + +"hast-util-sanitize@npm:^5.0.0": + version: 5.0.2 + resolution: "hast-util-sanitize@npm:5.0.2" + dependencies: + "@types/hast": "npm:^3.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" + checksum: 10c0/20951652078a8c21341c1c9a84f90015b2ba01cc41fa16772f122c65cda26a7adb0501fdeba5c8e37e40e2632447e8fe455d0dd2dc27d39663baacca76f2ecb6 + languageName: node + linkType: hard + +"hast-util-to-jsx-runtime@npm:^2.0.0": + version: 2.3.6 + resolution: "hast-util-to-jsx-runtime@npm:2.3.6" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + hast-util-whitespace: "npm:^3.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + style-to-js: "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/27297e02848fe37ef219be04a26ce708d17278a175a807689e94a821dcffc88aa506d62c3a85beed1f9a8544f7211bdcbcde0528b7b456a57c2e342c3fd11056 + languageName: node + linkType: hard + +"hast-util-to-parse5@npm:^8.0.0": + version: 8.0.1 + resolution: "hast-util-to-parse5@npm:8.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/8e8a1817c7ff8906ac66e7201b1b8d19d9e1b705e695a6e71620270d498d982ec1ecc0e227bd517f723e91e7fdfb90ef75f9ae64d14b3b65239a7d5e1194d7dd + languageName: node + linkType: hard + +"hast-util-whitespace@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-whitespace@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/b898bc9fe27884b272580d15260b6bbdabe239973a147e97fa98c45fa0ffec967a481aaa42291ec34fb56530dc2d484d473d7e2bae79f39c83f3762307edfea8 + languageName: node + linkType: hard + +"hastscript@npm:^9.0.0": + version: 9.0.1 + resolution: "hastscript@npm:9.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + hast-util-parse-selector: "npm:^4.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + checksum: 10c0/18dc8064e5c3a7a2ae862978e626b97a254e1c8a67ee9d0c9f06d373bba155ed805fc5b5ce21b990fb7bc174624889e5e1ce1cade264f1b1d58b48f994bc85ce + languageName: node + linkType: hard + "hermes-estree@npm:0.25.1": version: 0.25.1 resolution: "hermes-estree@npm:0.25.1" @@ -4025,6 +4296,20 @@ __metadata: languageName: node linkType: hard +"html-url-attributes@npm:^3.0.0": + version: 3.0.1 + resolution: "html-url-attributes@npm:3.0.1" + checksum: 10c0/496e4908aa8b77665f348b4b03521901794f648b8ac34a581022cd6f2c97934d5c910cd91bc6593bbf2994687549037bc2520fcdc769b31484f29ffdd402acd0 + languageName: node + linkType: hard + +"html-void-elements@npm:^3.0.0": + version: 3.0.0 + resolution: "html-void-elements@npm:3.0.0" + checksum: 10c0/a8b9ec5db23b7c8053876dad73a0336183e6162bf6d2677376d8b38d654fdc59ba74fdd12f8812688f7db6fad451210c91b300e472afc0909224e0a44c8610d2 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" @@ -4143,6 +4428,13 @@ __metadata: languageName: node linkType: hard +"inline-style-parser@npm:0.2.7": + version: 0.2.7 + resolution: "inline-style-parser@npm:0.2.7" + checksum: 10c0/d884d76f84959517430ae6c22f0bda59bb3f58f539f99aac75a8d786199ec594ed648c6ab4640531f9fc244b0ed5cd8c458078e592d016ef06de793beb1debff + languageName: node + linkType: hard + "internal-slot@npm:^1.1.0": version: 1.1.0 resolution: "internal-slot@npm:1.1.0" @@ -4161,6 +4453,23 @@ __metadata: languageName: node linkType: hard +"is-alphabetical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphabetical@npm:2.0.1" + checksum: 10c0/932367456f17237533fd1fc9fe179df77957271020b83ea31da50e5cc472d35ef6b5fb8147453274ffd251134472ce24eb6f8d8398d96dee98237cdb81a6c9a7 + languageName: node + linkType: hard + +"is-alphanumerical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphanumerical@npm:2.0.1" + dependencies: + is-alphabetical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + checksum: 10c0/4b35c42b18e40d41378293f82a3ecd9de77049b476f748db5697c297f686e1e05b072a6aaae2d16f54d2a57f85b00cbbe755c75f6d583d1c77d6657bd0feb5a2 + languageName: node + linkType: hard + "is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": version: 3.0.5 resolution: "is-array-buffer@npm:3.0.5" @@ -4241,6 +4550,13 @@ __metadata: languageName: node linkType: hard +"is-decimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-decimal@npm:2.0.1" + checksum: 10c0/8085dd66f7d82f9de818fba48b9e9c0429cb4291824e6c5f2622e96b9680b54a07a624cfc663b24148b8e853c62a1c987cfe8b0b5a13f5156991afaf6736e334 + languageName: node + linkType: hard + "is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": version: 2.2.1 resolution: "is-docker@npm:2.2.1" @@ -4295,6 +4611,13 @@ __metadata: languageName: node linkType: hard +"is-hexadecimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-hexadecimal@npm:2.0.1" + checksum: 10c0/3eb60fe2f1e2bbc760b927dcad4d51eaa0c60138cf7fc671803f66353ad90c301605b502c7ea4c6bb0548e1c7e79dfd37b73b632652e3b76030bba603a7e9626 + languageName: node + linkType: hard + "is-interactive@npm:^1.0.0": version: 1.0.0 resolution: "is-interactive@npm:1.0.0" @@ -4326,7 +4649,7 @@ __metadata: languageName: node linkType: hard -"is-plain-obj@npm:^4.1.0": +"is-plain-obj@npm:^4.0.0, is-plain-obj@npm:^4.1.0": version: 4.1.0 resolution: "is-plain-obj@npm:4.1.0" checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e @@ -4751,6 +5074,13 @@ __metadata: languageName: node linkType: hard +"longest-streak@npm:^3.0.0": + version: 3.1.0 + resolution: "longest-streak@npm:3.1.0" + checksum: 10c0/7c2f02d0454b52834d1bcedef79c557bd295ee71fdabb02d041ff3aa9da48a90b5df7c0409156dedbc4df9b65da18742652aaea4759d6ece01f08971af6a7eaa + languageName: node + linkType: hard + "loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -4831,6 +5161,13 @@ __metadata: languageName: node linkType: hard +"markdown-table@npm:^3.0.0": + version: 3.0.4 + resolution: "markdown-table@npm:3.0.4" + checksum: 10c0/1257b31827629a54c24a5030a3dac952256c559174c95ce3ef89bebd6bff0cb1444b1fd667b1a1bb53307f83278111505b3e26f0c4e7b731e0060d435d2d930b + languageName: node + linkType: hard + "matcher@npm:^3.0.0": version: 3.0.0 resolution: "matcher@npm:3.0.0" @@ -4847,6 +5184,545 @@ __metadata: languageName: node linkType: hard +"mdast-util-find-and-replace@npm:^3.0.0": + version: 3.0.2 + resolution: "mdast-util-find-and-replace@npm:3.0.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + escape-string-regexp: "npm:^5.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/c8417a35605d567772ff5c1aa08363ff3010b0d60c8ea68c53cba09bf25492e3dd261560425c1756535f3b7107f62e7ff3857cdd8fb1e62d1b2cc2ea6e074ca2 + languageName: node + linkType: hard + +"mdast-util-from-markdown@npm:^2.0.0": + version: 2.0.2 + resolution: "mdast-util-from-markdown@npm:2.0.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark: "npm:^4.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/76eb2bd2c6f7a0318087c73376b8af6d7561c1e16654e7667e640f391341096c56142618fd0ff62f6d39e5ab4895898b9789c84cd7cec2874359a437a0e1ff15 + languageName: node + linkType: hard + +"mdast-util-gfm-autolink-literal@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-gfm-autolink-literal@npm:2.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + ccount: "npm:^2.0.0" + devlop: "npm:^1.0.0" + mdast-util-find-and-replace: "npm:^3.0.0" + micromark-util-character: "npm:^2.0.0" + checksum: 10c0/963cd22bd42aebdec7bdd0a527c9494d024d1ad0739c43dc040fee35bdfb5e29c22564330a7418a72b5eab51d47a6eff32bc0255ef3ccb5cebfe8970e91b81b6 + languageName: node + linkType: hard + +"mdast-util-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "mdast-util-gfm-footnote@npm:2.1.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + checksum: 10c0/8ab965ee6be3670d76ec0e95b2ba3101fc7444eec47564943ab483d96ac17d29da2a4e6146a2a288be30c21b48c4f3938a1e54b9a46fbdd321d49a5bc0077ed0 + languageName: node + linkType: hard + +"mdast-util-gfm-strikethrough@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-strikethrough@npm:2.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/b053e93d62c7545019bd914271ea9e5667ad3b3b57d16dbf68e56fea39a7e19b4a345e781312714eb3d43fdd069ff7ee22a3ca7f6149dfa774554f19ce3ac056 + languageName: node + linkType: hard + +"mdast-util-gfm-table@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-table@npm:2.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + markdown-table: "npm:^3.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/128af47c503a53bd1c79f20642561e54a510ad5e2db1e418d28fefaf1294ab839e6c838e341aef5d7e404f9170b9ca3d1d89605f234efafde93ee51174a6e31e + languageName: node + linkType: hard + +"mdast-util-gfm-task-list-item@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-task-list-item@npm:2.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/258d725288482b636c0a376c296431390c14b4f29588675297cb6580a8598ed311fc73ebc312acfca12cc8546f07a3a285a53a3b082712e2cbf5c190d677d834 + languageName: node + linkType: hard + +"mdast-util-gfm@npm:^3.0.0": + version: 3.1.0 + resolution: "mdast-util-gfm@npm:3.1.0" + dependencies: + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-gfm-autolink-literal: "npm:^2.0.0" + mdast-util-gfm-footnote: "npm:^2.0.0" + mdast-util-gfm-strikethrough: "npm:^2.0.0" + mdast-util-gfm-table: "npm:^2.0.0" + mdast-util-gfm-task-list-item: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/4bedcfb6a20e39901c8772f0d2bb2d7a64ae87a54c13cbd92eec062cf470fbb68c2ad754e149af5b30794e2de61c978ab1de1ace03c0c40f443ca9b9b8044f81 + languageName: node + linkType: hard + +"mdast-util-mdx-expression@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdx-expression@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/9a1e57940f66431f10312fa239096efa7627f375e7933b5d3162c0b5c1712a72ac87447aff2b6838d2bbd5c1311b188718cc90b33b67dc67a88550e0a6ef6183 + languageName: node + linkType: hard + +"mdast-util-mdx-jsx@npm:^3.0.0": + version: 3.2.0 + resolution: "mdast-util-mdx-jsx@npm:3.2.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + ccount: "npm:^2.0.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + parse-entities: "npm:^4.0.0" + stringify-entities: "npm:^4.0.0" + unist-util-stringify-position: "npm:^4.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3acadaf3b962254f7ad2990fed4729961dc0217ca31fde9917986e880843f3ecf3392b1f22d569235cacd180d50894ad266db7af598aedca69d330d33c7ac613 + languageName: node + linkType: hard + +"mdast-util-mdxjs-esm@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdxjs-esm@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/5bda92fc154141705af2b804a534d891f28dac6273186edf1a4c5e3f045d5b01dbcac7400d27aaf91b7e76e8dce007c7b2fdf136c11ea78206ad00bdf9db46bc + languageName: node + linkType: hard + +"mdast-util-phrasing@npm:^4.0.0": + version: 4.1.0 + resolution: "mdast-util-phrasing@npm:4.1.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/bf6c31d51349aa3d74603d5e5a312f59f3f65662ed16c58017169a5fb0f84ca98578f626c5ee9e4aa3e0a81c996db8717096705521bddb4a0185f98c12c9b42f + languageName: node + linkType: hard + +"mdast-util-to-hast@npm:^13.0.0": + version: 13.2.1 + resolution: "mdast-util-to-hast@npm:13.2.1" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + trim-lines: "npm:^3.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/3eeaf28a5e84e1e08e6d54a1a8a06c0fca88cb5d36f4cf8086f0177248d1ce6e4e751f4ad0da19a3dea1c6ea61bd80784acc3ae021e44ceeb21aa5413a375e43 + languageName: node + linkType: hard + +"mdast-util-to-markdown@npm:^2.0.0": + version: 2.1.2 + resolution: "mdast-util-to-markdown@npm:2.1.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + longest-streak: "npm:^3.0.0" + mdast-util-phrasing: "npm:^4.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + unist-util-visit: "npm:^5.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/4649722a6099f12e797bd8d6469b2b43b44e526b5182862d9c7766a3431caad2c0112929c538a972f214e63c015395e5d3f54bd81d9ac1b16e6d8baaf582f749 + languageName: node + linkType: hard + +"mdast-util-to-string@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-to-string@npm:4.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + checksum: 10c0/2d3c1af29bf3fe9c20f552ee9685af308002488f3b04b12fa66652c9718f66f41a32f8362aa2d770c3ff464c034860b41715902ada2306bb0a055146cef064d7 + languageName: node + linkType: hard + +"micromark-core-commonmark@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-core-commonmark@npm:2.0.3" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-destination: "npm:^2.0.0" + micromark-factory-label: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-factory-title: "npm:^2.0.0" + micromark-factory-whitespace: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-html-tag-name: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bd4a794fdc9e88dbdf59eaf1c507ddf26e5f7ddf4e52566c72239c0f1b66adbcd219ba2cd42350debbe24471434d5f5e50099d2b3f4e5762ca222ba8e5b549ee + languageName: node + linkType: hard + +"micromark-extension-gfm-autolink-literal@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-autolink-literal@npm:2.1.0" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/84e6fbb84ea7c161dfa179665dc90d51116de4c28f3e958260c0423e5a745372b7dcbc87d3cde98213b532e6812f847eef5ae561c9397d7f7da1e59872ef3efe + languageName: node + linkType: hard + +"micromark-extension-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-footnote@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/d172e4218968b7371b9321af5cde8c77423f73b233b2b0fcf3ff6fd6f61d2e0d52c49123a9b7910612478bf1f0d5e88c75a3990dd68f70f3933fe812b9f77edc + languageName: node + linkType: hard + +"micromark-extension-gfm-strikethrough@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-strikethrough@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/ef4f248b865bdda71303b494671b7487808a340b25552b11ca6814dff3fcfaab9be8d294643060bbdb50f79313e4a686ab18b99cbe4d3ee8a4170fcd134234fb + languageName: node + linkType: hard + +"micromark-extension-gfm-table@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-extension-gfm-table@npm:2.1.1" + dependencies: + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/04bc00e19b435fa0add62cd029d8b7eb6137522f77832186b1d5ef34544a9bd030c9cf85e92ddfcc5c31f6f0a58a43d4b96dba4fc21316037c734630ee12c912 + languageName: node + linkType: hard + +"micromark-extension-gfm-tagfilter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-tagfilter@npm:2.0.0" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/995558843fff137ae4e46aecb878d8a4691cdf23527dcf1e2f0157d66786be9f7bea0109c52a8ef70e68e3f930af811828ba912239438e31a9cfb9981f44d34d + languageName: node + linkType: hard + +"micromark-extension-gfm-task-list-item@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-task-list-item@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/78aa537d929e9309f076ba41e5edc99f78d6decd754b6734519ccbbfca8abd52e1c62df68d41a6ae64d2a3fc1646cea955893c79680b0b4385ced4c52296181f + languageName: node + linkType: hard + +"micromark-extension-gfm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-gfm@npm:3.0.0" + dependencies: + micromark-extension-gfm-autolink-literal: "npm:^2.0.0" + micromark-extension-gfm-footnote: "npm:^2.0.0" + micromark-extension-gfm-strikethrough: "npm:^2.0.0" + micromark-extension-gfm-table: "npm:^2.0.0" + micromark-extension-gfm-tagfilter: "npm:^2.0.0" + micromark-extension-gfm-task-list-item: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/970e28df6ebdd7c7249f52a0dda56e0566fbfa9ae56c8eeeb2445d77b6b89d44096880cd57a1c01e7821b1f4e31009109fbaca4e89731bff7b83b8519690e5d9 + languageName: node + linkType: hard + +"micromark-factory-destination@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-destination@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bbafcf869cee5bf511161354cb87d61c142592fbecea051000ff116068dc85216e6d48519d147890b9ea5d7e2864a6341c0c09d9948c203bff624a80a476023c + languageName: node + linkType: hard + +"micromark-factory-label@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-label@npm:2.0.1" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/0137716b4ecb428114165505e94a2f18855c8bbea21b07a8b5ce514b32a595ed789d2b967125718fc44c4197ceaa48f6609d58807a68e778138d2e6b91b824e8 + languageName: node + linkType: hard + +"micromark-factory-space@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-space@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f9ed43f1c0652d8d898de0ac2be3f77f776fffe7dd96bdbba1e02d7ce33d3853c6ff5daa52568fc4fa32cdf3a62d86b85ead9b9189f7211e1d69ff2163c450fb + languageName: node + linkType: hard + +"micromark-factory-title@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-title@npm:2.0.1" + dependencies: + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/e72fad8d6e88823514916890099a5af20b6a9178ccf78e7e5e05f4de99bb8797acb756257d7a3a57a53854cb0086bf8aab15b1a9e9db8982500dd2c9ff5948b6 + languageName: node + linkType: hard + +"micromark-factory-whitespace@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-whitespace@npm:2.0.1" + dependencies: + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/20a1ec58698f24b766510a309b23a10175034fcf1551eaa9da3adcbed3e00cd53d1ebe5f030cf873f76a1cec3c34eb8c50cc227be3344caa9ed25d56cf611224 + languageName: node + linkType: hard + +"micromark-util-character@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-util-character@npm:2.1.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/d3fe7a5e2c4060fc2a076f9ce699c82a2e87190a3946e1e5eea77f563869b504961f5668d9c9c014724db28ac32fa909070ea8b30c3a39bd0483cc6c04cc76a1 + languageName: node + linkType: hard + +"micromark-util-chunked@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-chunked@npm:2.0.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/b68c0c16fe8106949537bdcfe1be9cf36c0ccd3bc54c4007003cb0984c3750b6cdd0fd77d03f269a3382b85b0de58bde4f6eedbe7ecdf7244759112289b1ab56 + languageName: node + linkType: hard + +"micromark-util-classify-character@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-classify-character@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/8a02e59304005c475c332f581697e92e8c585bcd45d5d225a66c1c1b14ab5a8062705188c2ccec33cc998d33502514121478b2091feddbc751887fc9c290ed08 + languageName: node + linkType: hard + +"micromark-util-combine-extensions@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-combine-extensions@npm:2.0.1" + dependencies: + micromark-util-chunked: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f15e282af24c8372cbb10b9b0b3e2c0aa681fea0ca323a44d6bc537dc1d9382c819c3689f14eaa000118f5a163245358ce6276b2cda9a84439cdb221f5d86ae7 + languageName: node + linkType: hard + +"micromark-util-decode-numeric-character-reference@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.2" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/9c8a9f2c790e5593ffe513901c3a110e9ec8882a08f466da014112a25e5059b51551ca0aeb7ff494657d86eceb2f02ee556c6558b8d66aadc61eae4a240da0df + languageName: node + linkType: hard + +"micromark-util-decode-string@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-decode-string@npm:2.0.1" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/f24d75b2e5310be6e7b6dee532e0d17d3bf46996841d6295f2a9c87a2046fff4ab603c52ab9d7a7a6430a8b787b1574ae895849c603d262d1b22eef71736b5cb + languageName: node + linkType: hard + +"micromark-util-encode@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-encode@npm:2.0.1" + checksum: 10c0/b2b29f901093845da8a1bf997ea8b7f5e061ffdba85070dfe14b0197c48fda64ffcf82bfe53c90cf9dc185e69eef8c5d41cae3ba918b96bc279326921b59008a + languageName: node + linkType: hard + +"micromark-util-html-tag-name@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-html-tag-name@npm:2.0.1" + checksum: 10c0/ae80444db786fde908e9295f19a27a4aa304171852c77414516418650097b8afb401961c9edb09d677b06e97e8370cfa65638dde8438ebd41d60c0a8678b85b9 + languageName: node + linkType: hard + +"micromark-util-normalize-identifier@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-normalize-identifier@npm:2.0.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/5299265fa360769fc499a89f40142f10a9d4a5c3dd8e6eac8a8ef3c2e4a6570e4c009cf75ea46dce5ee31c01f25587bde2f4a5cc0a935584ae86dd857f2babbd + languageName: node + linkType: hard + +"micromark-util-resolve-all@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-resolve-all@npm:2.0.1" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bb6ca28764696bb479dc44a2d5b5fe003e7177aeae1d6b0d43f24cc223bab90234092d9c3ce4a4d2b8df095ccfd820537b10eb96bb7044d635f385d65a4c984a + languageName: node + linkType: hard + +"micromark-util-sanitize-uri@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-sanitize-uri@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/60e92166e1870fd4f1961468c2651013ff760617342918e0e0c3c4e872433aa2e60c1e5a672bfe5d89dc98f742d6b33897585cf86ae002cda23e905a3c02527c + languageName: node + linkType: hard + +"micromark-util-subtokenize@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-util-subtokenize@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bee69eece4393308e657c293ba80d92ebcb637e5f55e21dcf9c3fa732b91a8eda8ac248d76ff375e675175bfadeae4712e5158ef97eef1111789da1ce7ab5067 + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-symbol@npm:2.0.1" + checksum: 10c0/f2d1b207771e573232436618e78c5e46cd4b5c560dd4a6d63863d58018abbf49cb96ec69f7007471e51434c60de3c9268ef2bf46852f26ff4aacd10f9da16fe9 + languageName: node + linkType: hard + +"micromark-util-types@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-types@npm:2.0.2" + checksum: 10c0/c8c15b96c858db781c4393f55feec10004bf7df95487636c9a9f7209e51002a5cca6a047c5d2a5dc669ff92da20e57aaa881e81a268d9ccadb647f9dce305298 + languageName: node + linkType: hard + +"micromark@npm:^4.0.0": + version: 4.0.2 + resolution: "micromark@npm:4.0.2" + dependencies: + "@types/debug": "npm:^4.0.0" + debug: "npm:^4.0.0" + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/07462287254219d6eda6eac8a3cebaff2994e0575499e7088027b825105e096e4f51e466b14b2a81b71933a3b6c48ee069049d87bc2c2127eee50d9cc69e8af6 + languageName: node + linkType: hard + "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -5390,6 +6266,21 @@ __metadata: languageName: node linkType: hard +"parse-entities@npm:^4.0.0": + version: 4.0.2 + resolution: "parse-entities@npm:4.0.2" + dependencies: + "@types/unist": "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + character-reference-invalid: "npm:^2.0.0" + decode-named-character-reference: "npm:^1.0.0" + is-alphanumerical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + is-hexadecimal: "npm:^2.0.0" + checksum: 10c0/a13906b1151750b78ed83d386294066daf5fb559e08c5af9591b2d98cc209123103016a01df776f65f8219ad26652d6d6b210d0974d452049cddfc53a8916c34 + languageName: node + linkType: hard + "parse-ms@npm:^4.0.0": version: 4.0.0 resolution: "parse-ms@npm:4.0.0" @@ -5397,6 +6288,15 @@ __metadata: languageName: node linkType: hard +"parse5@npm:^7.0.0": + version: 7.3.0 + resolution: "parse5@npm:7.3.0" + dependencies: + entities: "npm:^6.0.0" + checksum: 10c0/7fd2e4e247e85241d6f2a464d0085eed599a26d7b0a5233790c49f53473232eb85350e8133344d9b3fd58b89339e7ad7270fe1f89d28abe50674ec97b87f80b5 + languageName: node + linkType: hard + "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" @@ -5559,6 +6459,13 @@ __metadata: languageName: node linkType: hard +"property-information@npm:^7.0.0": + version: 7.1.0 + resolution: "property-information@npm:7.1.0" + checksum: 10c0/e0fe22cff26103260ad0e82959229106563fa115a54c4d6c183f49d88054e489cc9f23452d3ad584179dc13a8b7b37411a5df873746b5e4086c865874bfa968e + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.3 resolution: "pump@npm:3.0.3" @@ -5612,6 +6519,28 @@ __metadata: languageName: node linkType: hard +"react-markdown@npm:^10.1.0": + version: 10.1.0 + resolution: "react-markdown@npm:10.1.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + hast-util-to-jsx-runtime: "npm:^2.0.0" + html-url-attributes: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + remark-parse: "npm:^11.0.0" + remark-rehype: "npm:^11.0.0" + unified: "npm:^11.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + peerDependencies: + "@types/react": ">=18" + react: ">=18" + checksum: 10c0/4a5dc7d15ca6d05e9ee95318c1904f83b111a76f7588c44f50f1d54d4c97193b84e4f64c4b592057c989228238a2590306cedd0c4d398e75da49262b2b5ae1bf + languageName: node + linkType: hard + "react-number-format@npm:^5.4.4": version: 5.4.4 resolution: "react-number-format@npm:5.4.4" @@ -5771,6 +6700,77 @@ __metadata: languageName: node linkType: hard +"rehype-raw@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-raw@npm:7.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + hast-util-raw: "npm:^9.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/1435b4b6640a5bc3abe3b2133885c4dbff5ef2190ef9cfe09d6a63f74dd7d7ffd0cede70603278560ccf1acbfb9da9faae4b68065a28bc5aa88ad18e40f32d52 + languageName: node + linkType: hard + +"rehype-sanitize@npm:^6.0.0": + version: 6.0.0 + resolution: "rehype-sanitize@npm:6.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + hast-util-sanitize: "npm:^5.0.0" + checksum: 10c0/43d6c056e63c994cf56e5ee0e157052d2030dc5ac160845ee494af9a26e5906bf5ec5af56c7d90c99f9c4dc0091e45a48a168618135fb6c64a76481ad3c449e9 + languageName: node + linkType: hard + +"remark-gfm@npm:^4.0.1": + version: 4.0.1 + resolution: "remark-gfm@npm:4.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-gfm: "npm:^3.0.0" + micromark-extension-gfm: "npm:^3.0.0" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/427ecc6af3e76222662061a5f670a3e4e33ec5fffe2cabf04034da6a3f9a1bda1fc023e838a636385ba314e66e2bebbf017ca61ebea357eb0f5200fe0625a4b7 + languageName: node + linkType: hard + +"remark-parse@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-parse@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/6eed15ddb8680eca93e04fcb2d1b8db65a743dcc0023f5007265dda558b09db595a087f622062ccad2630953cd5cddc1055ce491d25a81f3317c858348a8dd38 + languageName: node + linkType: hard + +"remark-rehype@npm:^11.0.0": + version: 11.1.2 + resolution: "remark-rehype@npm:11.1.2" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + mdast-util-to-hast: "npm:^13.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/f9eccacfb596d9605581dc05bfad28635d6ded5dd0a18e88af5fd4df0d3fcf9612e1501d4513bc2164d833cfe9636dab20400080b09e53f155c6e1442a1231fb + languageName: node + linkType: hard + +"remark-stringify@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-stringify@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/0cdb37ce1217578f6f847c7ec9f50cbab35df5b9e3903d543e74b405404e67c07defcb23cd260a567b41b769400f6de03c2c3d9cd6ae7a6707d5c8d89ead489f + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -6331,6 +7331,13 @@ __metadata: languageName: node linkType: hard +"space-separated-tokens@npm:^2.0.0": + version: 2.0.2 + resolution: "space-separated-tokens@npm:2.0.2" + checksum: 10c0/6173e1d903dca41dcab6a2deed8b4caf61bd13b6d7af8374713500570aa929ff9414ae09a0519f4f8772df993300305a395d4871f35bc4ca72b6db57e1f30af8 + languageName: node + linkType: hard + "sprintf-js@npm:^1.1.2": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -6471,6 +7478,16 @@ __metadata: languageName: node linkType: hard +"stringify-entities@npm:^4.0.0": + version: 4.0.4 + resolution: "stringify-entities@npm:4.0.4" + dependencies: + character-entities-html4: "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + checksum: 10c0/537c7e656354192406bdd08157d759cd615724e9d0873602d2c9b2f6a5c0a8d0b1d73a0a08677848105c5eebac6db037b57c0b3a4ec86331117fa7319ed50448 + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -6517,6 +7534,24 @@ __metadata: languageName: node linkType: hard +"style-to-js@npm:^1.0.0": + version: 1.1.21 + resolution: "style-to-js@npm:1.1.21" + dependencies: + style-to-object: "npm:1.0.14" + checksum: 10c0/94231aa80f58f442c3a5ae01a21d10701e5d62f96b4b3e52eab3499077ee52df203cc0df4a1a870707f5e99470859136ea8657b782a5f4ca7934e0ffe662a588 + languageName: node + linkType: hard + +"style-to-object@npm:1.0.14": + version: 1.0.14 + resolution: "style-to-object@npm:1.0.14" + dependencies: + inline-style-parser: "npm:0.2.7" + checksum: 10c0/854d9e9b77afc336e6d7b09348e7939f2617b34eb0895824b066d8cd1790284cb6d8b2ba36be88025b2595d715dba14b299ae76e4628a366541106f639e13679 + languageName: node + linkType: hard + "sumchecker@npm:^3.0.1": version: 3.0.1 resolution: "sumchecker@npm:3.0.1" @@ -6645,6 +7680,13 @@ __metadata: languageName: node linkType: hard +"trim-lines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-lines@npm:3.0.1" + checksum: 10c0/3a1611fa9e52aa56a94c69951a9ea15b8aaad760eaa26c56a65330dc8adf99cb282fc07cc9d94968b7d4d88003beba220a7278bbe2063328eb23fb56f9509e94 + languageName: node + linkType: hard + "triple-beam@npm:^1.3.0, triple-beam@npm:^1.4.1": version: 1.4.1 resolution: "triple-beam@npm:1.4.1" @@ -6652,6 +7694,13 @@ __metadata: languageName: node linkType: hard +"trough@npm:^2.0.0": + version: 2.2.0 + resolution: "trough@npm:2.2.0" + checksum: 10c0/58b671fc970e7867a48514168894396dd94e6d9d6456aca427cc299c004fe67f35ed7172a36449086b2edde10e78a71a284ec0076809add6834fb8f857ccb9b0 + languageName: node + linkType: hard + "truncate-utf8-bytes@npm:^1.0.0": version: 1.0.2 resolution: "truncate-utf8-bytes@npm:1.0.2" @@ -6818,6 +7867,21 @@ __metadata: languageName: node linkType: hard +"unified@npm:^11.0.0": + version: 11.0.5 + resolution: "unified@npm:11.0.5" + dependencies: + "@types/unist": "npm:^3.0.0" + bail: "npm:^2.0.0" + devlop: "npm:^1.0.0" + extend: "npm:^3.0.0" + is-plain-obj: "npm:^4.0.0" + trough: "npm:^2.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/53c8e685f56d11d9d458a43e0e74328a4d6386af51c8ac37a3dcabec74ce5026da21250590d4aff6733ccd7dc203116aae2b0769abc18cdf9639a54ae528dfc9 + languageName: node + linkType: hard + "unique-filename@npm:^4.0.0": version: 4.0.0 resolution: "unique-filename@npm:4.0.0" @@ -6836,6 +7900,54 @@ __metadata: languageName: node linkType: hard +"unist-util-is@npm:^6.0.0": + version: 6.0.1 + resolution: "unist-util-is@npm:6.0.1" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/5a487d390193811d37a68264e204dbc7c15c40b8fc29b5515a535d921d071134f571d7b5cbd59bcd58d5ce1c0ab08f20fc4a1f0df2287a249c979267fc32ce06 + languageName: node + linkType: hard + +"unist-util-position@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-position@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dde3b31e314c98f12b4dc6402f9722b2bf35e96a4f2d463233dd90d7cde2d4928074a7a11eff0a5eb1f4e200f27fc1557e0a64a7e8e4da6558542f251b1b7400 + languageName: node + linkType: hard + +"unist-util-stringify-position@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-stringify-position@npm:4.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dfe1dbe79ba31f589108cb35e523f14029b6675d741a79dea7e5f3d098785045d556d5650ec6a8338af11e9e78d2a30df12b1ee86529cded1098da3f17ee999e + languageName: node + linkType: hard + +"unist-util-visit-parents@npm:^6.0.0": + version: 6.0.2 + resolution: "unist-util-visit-parents@npm:6.0.2" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/f1e4019dbd930301825895e3737b1ee0cd682f7622ddd915062135cbb39f8c090aaece3a3b5eae1f2ea52ec33f0931abb8f8a8b5c48a511a4203e3d360a8cd49 + languageName: node + linkType: hard + +"unist-util-visit@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-visit@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/51434a1d80252c1540cce6271a90fd1a106dbe624997c09ed8879279667fb0b2d3a685e02e92bf66598dcbe6cdffa7a5f5fb363af8fdf90dda6c855449ae39a5 + languageName: node + linkType: hard + "universalify@npm:^0.1.0": version: 0.1.2 resolution: "universalify@npm:0.1.2" @@ -6967,9 +8079,39 @@ __metadata: languageName: node linkType: hard -"vite@npm:^7.2.6": - version: 7.2.6 - resolution: "vite@npm:7.2.6" +"vfile-location@npm:^5.0.0": + version: 5.0.3 + resolution: "vfile-location@npm:5.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/1711f67802a5bc175ea69750d59863343ed43d1b1bb25c0a9063e4c70595e673e53e2ed5cdbb6dcdc370059b31605144d95e8c061b9361bcc2b036b8f63a4966 + languageName: node + linkType: hard + +"vfile-message@npm:^4.0.0": + version: 4.0.3 + resolution: "vfile-message@npm:4.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/33d9f219610d27987689bb14fa5573d2daa146941d1a05416dd7702c4215b23f44ed81d059e70d0e4e24f9a57d5f4dc9f18d35a993f04cf9446a7abe6d72d0c0 + languageName: node + linkType: hard + +"vfile@npm:^6.0.0": + version: 6.0.3 + resolution: "vfile@npm:6.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/e5d9eb4810623f23758cfc2205323e33552fb5972e5c2e6587babe08fe4d24859866277404fb9e2a20afb71013860d96ec806cb257536ae463c87d70022ab9ef + languageName: node + linkType: hard + +"vite@npm:^7.2.7": + version: 7.2.7 + resolution: "vite@npm:7.2.7" dependencies: esbuild: "npm:^0.25.0" fdir: "npm:^6.5.0" @@ -7018,7 +8160,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/d444a159ab8f0f854d596d1938f201b449d59ed4d336e587be9dc89005467214d85848c212c2495f76a8421372ffe4d061d023d659600f1aaa3ba5ac13e804f7 + checksum: 10c0/0c502d9eb898d9c05061dbd8fd199f280b524bbb4c12ab5f88c7b12779947386684a269e4dd0aa424aa35bcd857f1aa44aadb9ea764702a5043af433052455b5 languageName: node linkType: hard @@ -7038,6 +8180,13 @@ __metadata: languageName: node linkType: hard +"web-namespaces@npm:^2.0.0": + version: 2.0.1 + resolution: "web-namespaces@npm:2.0.1" + checksum: 10c0/df245f466ad83bd5cd80bfffc1674c7f64b7b84d1de0e4d2c0934fb0782e0a599164e7197a4bce310ee3342fd61817b8047ff04f076a1ce12dd470584142a4bd + languageName: node + linkType: hard + "which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": version: 1.1.1 resolution: "which-boxed-primitive@npm:1.1.1" @@ -7328,3 +8477,10 @@ __metadata: checksum: 10c0/552849e4546c7760704d6509a5c412d57c62a1fa9e53169c939ba5e3d75f8cb3df50a64c3a22e6c3f1c8cc00de7543e4edd61ab5ae0c9169ba9a98e28303aba6 languageName: node linkType: hard + +"zwitch@npm:^2.0.0": + version: 2.0.4 + resolution: "zwitch@npm:2.0.4" + checksum: 10c0/3c7830cdd3378667e058ffdb4cf2bb78ac5711214e2725900873accb23f3dfe5f9e7e5a06dcdc5f29605da976fc45c26d9a13ca334d6eea2245a15e77b8fc06e + languageName: node + linkType: hard