From 9b87cd789e24a67be027f87b208f2b347e6ebd8f Mon Sep 17 00:00:00 2001 From: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Date: Fri, 30 Jan 2026 20:40:27 +0800 Subject: [PATCH] feat(ui): add Markdown rendering components Add CodeBlock, Markdown, StreamingMarkdown components with Shiki syntax highlighting, GFM support, and linkify utility. Co-Authored-By: Claude Opus 4.5 --- apps/web/app/page.tsx | 55 +- packages/ui/package.json | 10 +- .../ui/src/components/markdown/CodeBlock.tsx | 250 ++++ .../ui/src/components/markdown/Markdown.tsx | 301 +++++ .../components/markdown/StreamingMarkdown.tsx | 186 +++ packages/ui/src/components/markdown/index.ts | 4 + .../ui/src/components/markdown/linkify.ts | 195 +++ packages/ui/src/styles/globals.css | 14 + pnpm-lock.yaml | 1168 ++++++++++++++++- 9 files changed, 2130 insertions(+), 53 deletions(-) create mode 100644 packages/ui/src/components/markdown/CodeBlock.tsx create mode 100644 packages/ui/src/components/markdown/Markdown.tsx create mode 100644 packages/ui/src/components/markdown/StreamingMarkdown.tsx create mode 100644 packages/ui/src/components/markdown/index.ts create mode 100644 packages/ui/src/components/markdown/linkify.ts diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 5e476424..356262c3 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -1,7 +1,56 @@ "use client" -import { ComponentExample } from "@multica/ui/components/component-example"; +import { Markdown } from "@multica/ui/components/markdown" + +const MOCK_MD = `# Markdown 渲染器示例 + +这是一个 **Markdown** 渲染组件的演示页面,支持多种常见语法。 + +## 代码高亮 + +\`\`\`typescript +interface User { + id: string + name: string + email: string +} + +async function fetchUser(id: string): Promise { + const res = await fetch(\`/api/users/\${id}\`) + return res.json() +} +\`\`\` + +## 列表 + +- React 组件化架构 +- Shiki 语法高亮 +- GFM 表格和任务列表支持 + +## 表格 + +| 功能 | 状态 | 说明 | +|------|------|------| +| 代码高亮 | ✅ | 基于 Shiki | +| GFM 表格 | ✅ | remark-gfm | +| 流式渲染 | ✅ | StreamingMarkdown | + +## 引用 + +> 好的设计是尽可能少的设计。 +> — Dieter Rams + +行内代码示例:使用 \`cn()\` 工具函数合并 class。 + +这是一个 [链接示例](https://github.com)。 +` export default function Page() { - return ; -} \ No newline at end of file + return ( +
+
+ {MOCK_MD} +
+
+ ) +} diff --git a/packages/ui/package.json b/packages/ui/package.json index 17628c39..a1a81d0a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -9,6 +9,8 @@ "./lib/*": "./src/lib/*.ts", "./components/*": "./src/components/*.tsx", "./components/ui/*": "./src/components/ui/*.tsx", + "./components/markdown": "./src/components/markdown/index.ts", + "./components/markdown/*": "./src/components/markdown/*.tsx", "./hooks/*": "./src/hooks/*.ts" }, "dependencies": { @@ -23,12 +25,18 @@ "shadcn": "^3.7.0", "tailwind-merge": "^3.4.0", "tailwindcss": "^4", - "tw-animate-css": "^1.4.0" + "tw-animate-css": "^1.4.0", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1", + "rehype-raw": "^7.0.0", + "shiki": "^3.21.0", + "linkify-it": "^5.0.0" }, "devDependencies": { "@tailwindcss/postcss": "^4", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "@types/linkify-it": "^5.0.0", "typescript": "catalog:" } } diff --git a/packages/ui/src/components/markdown/CodeBlock.tsx b/packages/ui/src/components/markdown/CodeBlock.tsx new file mode 100644 index 00000000..a13b41ab --- /dev/null +++ b/packages/ui/src/components/markdown/CodeBlock.tsx @@ -0,0 +1,250 @@ +import * as React from 'react' +import { codeToHtml, bundledLanguages, type BundledLanguage } from 'shiki' +import { cn } from '@multica/ui/lib/utils' + +export interface CodeBlockProps { + code: string + language?: string + className?: string + /** + * Render mode affects code block styling: + * - 'terminal': Minimal, keeps control chars visible + * - 'minimal': Clean code, basic styling + * - 'full': Rich styling with background, copy button, etc. + */ + mode?: 'terminal' | 'minimal' | 'full' +} + +// Map common aliases to Shiki language names +const LANGUAGE_ALIASES: Record = { + js: 'javascript', + ts: 'typescript', + py: 'python', + sh: 'bash', + zsh: 'bash', + yml: 'yaml', + rb: 'ruby', + rs: 'rust', + kt: 'kotlin', + 'objective-c': 'objc', + objc: 'objc' +} + +// Simple LRU cache for highlighted code +const highlightCache = new Map() +const CACHE_MAX_SIZE = 200 + +function getCacheKey(code: string, lang: string): string { + return `${lang}:${code}` +} + +function isValidLanguage(lang: string): lang is BundledLanguage { + const normalized = LANGUAGE_ALIASES[lang] || lang + return normalized in bundledLanguages +} + +/** + * CodeBlock - Syntax highlighted code block using Shiki + * + * Uses Shiki dual themes with CSS variables for light/dark switching. + * No JS-based dark mode detection needed — theme switching is handled + * entirely via CSS (see globals.css for .shiki/.dark .shiki rules). + * + * @see https://shiki.style/guide/dual-themes + */ +export function CodeBlock({ + code, + language = 'text', + className, + mode = 'full' +}: CodeBlockProps): React.JSX.Element { + const [highlighted, setHighlighted] = React.useState(null) + const [isLoading, setIsLoading] = React.useState(true) + const [copied, setCopied] = React.useState(false) + + // Resolve language alias - keep as string to allow 'text' fallback + const langLower = language.toLowerCase() + const resolvedLang: string = LANGUAGE_ALIASES[langLower] || langLower + + React.useEffect(() => { + let cancelled = false + + async function highlight(): Promise { + const cacheKey = getCacheKey(code, resolvedLang) + + const cached = highlightCache.get(cacheKey) + if (cached) { + if (!cancelled) { + setHighlighted(cached) + setIsLoading(false) + } + return + } + + try { + // Use valid language or fallback to plaintext + const lang = isValidLanguage(resolvedLang) ? resolvedLang : 'text' + + // Dual themes: Shiki outputs CSS variables for both themes in one pass. + // CSS handles switching via .dark selector (see globals.css). + const html = await codeToHtml(code, { + lang, + themes: { + light: 'github-light', + dark: 'github-dark', + }, + defaultColor: false, + }) + + // Cache the result + if (highlightCache.size >= CACHE_MAX_SIZE) { + const firstKey = highlightCache.keys().next().value + if (firstKey) highlightCache.delete(firstKey) + } + highlightCache.set(cacheKey, html) + + if (!cancelled) { + setHighlighted(html) + setIsLoading(false) + } + } catch (error) { + // Fallback to plain text on error + console.warn(`Shiki highlighting failed for language "${resolvedLang}":`, error) + if (!cancelled) { + setHighlighted(null) + setIsLoading(false) + } + } + } + + highlight() + + return () => { + cancelled = true + } + }, [code, resolvedLang]) + + const handleCopy = React.useCallback(async () => { + try { + await navigator.clipboard.writeText(code) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } catch (err) { + console.error('Failed to copy code:', err) + } + }, [code]) + + // Terminal mode: raw monospace with minimal styling + if (mode === 'terminal') { + return ( +
+        {code}
+      
+ ) + } + + // Minimal mode: just syntax highlighting, no chrome + if (mode === 'minimal') { + if (isLoading || !highlighted) { + return ( +
+          {code}
+        
+ ) + } + + return ( +
+ ) + } + + // Full mode: rich styling with header and copy button + return ( +
+ {/* Language label + copy button */} +
+ + {resolvedLang !== 'text' ? resolvedLang : 'plain text'} + + +
+ + {/* Code content */} +
+ {isLoading || !highlighted ? ( +
+            {code}
+          
+ ) : ( +
+ )} +
+
+ ) +} + +/** + * InlineCode - Styled inline code span + * Features: subtle background (3%), subtle border (5%), 75% opacity text + */ +export function InlineCode({ + children, + className +}: { + children: React.ReactNode + className?: string +}): React.JSX.Element { + return ( + + {children} + + ) +} diff --git a/packages/ui/src/components/markdown/Markdown.tsx b/packages/ui/src/components/markdown/Markdown.tsx new file mode 100644 index 00000000..ccfb16bd --- /dev/null +++ b/packages/ui/src/components/markdown/Markdown.tsx @@ -0,0 +1,301 @@ +import * as React from 'react' +import ReactMarkdown, { type Components } from 'react-markdown' +import rehypeRaw from 'rehype-raw' +import remarkGfm from 'remark-gfm' +import { cn } from '@multica/ui/lib/utils' +import { CodeBlock, InlineCode } from './CodeBlock' +import { preprocessLinks } from './linkify' + +/** + * Render modes for markdown content: + * + * - 'terminal': Raw output with minimal formatting, control chars visible + * Best for: Debug output, raw logs, when you want to see exactly what's there + * + * - 'minimal': Clean rendering with syntax highlighting but no extra chrome + * Best for: Chat messages, inline content, when you want readability without clutter + * + * - 'full': Rich rendering with beautiful tables, styled code blocks, proper typography + * Best for: Documentation, long-form content, when presentation matters + */ +export type RenderMode = 'terminal' | 'minimal' | 'full' + +export interface MarkdownProps { + children: string + /** + * Render mode controlling formatting level + * @default 'minimal' + */ + mode?: RenderMode + className?: string + /** + * Message ID for memoization (optional) + * When provided, memoizes parsed blocks to avoid re-parsing during streaming + */ + id?: string + /** + * Callback when a URL is clicked + */ + onUrlClick?: (url: string) => void + /** + * Callback when a file path is clicked + */ + onFileClick?: (path: string) => void +} + +// File path detection regex - matches paths starting with /, ~/, or ./ +const FILE_PATH_REGEX = + /^(?:\/|~\/|\.\/)[\w\-./@]+\.(?:ts|tsx|js|jsx|mjs|cjs|md|json|yaml|yml|py|go|rs|css|scss|less|html|htm|txt|log|sh|bash|zsh|swift|kt|java|c|cpp|h|hpp|rb|php|xml|toml|ini|cfg|conf|env|sql|graphql|vue|svelte|astro|prisma)$/i + +/** + * Create custom components based on render mode + */ +function createComponents( + mode: RenderMode, + onUrlClick?: (url: string) => void, + onFileClick?: (path: string) => void +): Partial { + const baseComponents: Partial = { + // Links: Make clickable with callbacks + a: ({ href, children }) => { + const handleClick = (e: React.MouseEvent): void => { + e.preventDefault() + if (href) { + // Check if it's a file path + if (FILE_PATH_REGEX.test(href) && onFileClick) { + onFileClick(href) + } else if (onUrlClick) { + onUrlClick(href) + } else { + // Default: open in new window + window.open(href, '_blank', 'noopener,noreferrer') + } + } + } + + return ( + + {children} + + ) + } + } + + // Terminal mode: minimal formatting + if (mode === 'terminal') { + return { + ...baseComponents, + // No special code handling - just monospace + code: ({ children }) => {children}, + pre: ({ children }) =>
{children}
, + // Minimal paragraph spacing + p: ({ children }) =>

{children}

, + // Simple lists + ul: ({ children }) =>
    {children}
, + ol: ({ children }) =>
    {children}
, + li: ({ children }) =>
  • {children}
  • , + // Plain tables + table: ({ children }) => {children}
    , + th: ({ children }) => {children}, + td: ({ children }) => {children} + } + } + + // Minimal mode: clean with syntax highlighting + if (mode === 'minimal') { + return { + ...baseComponents, + // Inline code + code: ({ className, children, ...props }) => { + const match = /language-(\w+)/.exec(className || '') + const isBlock = + 'node' in props && props.node?.position?.start.line !== props.node?.position?.end.line + + // Block code - use CodeBlock with full mode + if (match || isBlock) { + const code = String(children).replace(/\n$/, '') + return + } + + // Inline code + return {children} + }, + pre: ({ children }) => <>{children}, + // Comfortable paragraph spacing + p: ({ children }) =>

    {children}

    , + // Styled lists + ul: ({ children }) => ( +
      + {children} +
    + ), + ol: ({ children }) =>
      {children}
    , + li: ({ children }) =>
  • {children}
  • , + // Clean tables + table: ({ children }) => ( +
    + {children}
    +
    + ), + thead: ({ children }) => {children}, + th: ({ children }) => ( + {children} + ), + td: ({ children }) => {children}, + // Headings - H1/H2 same size, differentiated by weight + h1: ({ children }) =>

    {children}

    , + h2: ({ children }) => ( +

    {children}

    + ), + h3: ({ children }) => ( +

    {children}

    + ), + // Blockquotes + blockquote: ({ children }) => ( +
    + {children} +
    + ), + // Horizontal rules + hr: () =>
    , + // Strong/emphasis + strong: ({ children }) => {children}, + em: ({ children }) => {children} + } + } + + // Full mode: rich styling + return { + ...baseComponents, + // Full code blocks with copy button + code: ({ className, children, ...props }) => { + const match = /language-(\w+)/.exec(className || '') + const isBlock = + 'node' in props && props.node?.position?.start.line !== props.node?.position?.end.line + + if (match || isBlock) { + const code = String(children).replace(/\n$/, '') + return + } + + return {children} + }, + pre: ({ children }) => <>{children}, + // Rich paragraph spacing + p: ({ children }) =>

    {children}

    , + // Styled lists + ul: ({ children }) => ( +
      + {children} +
    + ), + ol: ({ children }) =>
      {children}
    , + li: ({ children }) =>
  • {children}
  • , + // Beautiful tables + table: ({ children }) => ( +
    + {children}
    +
    + ), + thead: ({ children }) => {children}, + tbody: ({ children }) => {children}, + th: ({ children }) => {children}, + td: ({ children }) => {children}, + tr: ({ children }) => {children}, + // Rich headings + h1: ({ children }) =>

    {children}

    , + h2: ({ children }) => ( +

    {children}

    + ), + h3: ({ children }) =>

    {children}

    , + h4: ({ children }) =>

    {children}

    , + // Styled blockquotes + blockquote: ({ children }) => ( +
    + {children} +
    + ), + // Task lists (GFM) + input: ({ type, checked }) => { + if (type === 'checkbox') { + return ( + + ) + } + return + }, + // Horizontal rules + hr: () =>
    , + // Strong/emphasis + strong: ({ children }) => {children}, + em: ({ children }) => {children}, + del: ({ children }) => {children} + } +} + +/** + * Markdown - Customizable markdown renderer with multiple render modes + * + * Features: + * - Three render modes: terminal, minimal, full + * - Syntax highlighting via Shiki + * - GFM support (tables, task lists, strikethrough) + * - Clickable links and file paths + * - Memoization for streaming performance + */ +export function Markdown({ + children, + mode = 'minimal', + className, + onUrlClick, + onFileClick +}: MarkdownProps): React.JSX.Element { + const components = React.useMemo( + () => createComponents(mode, onUrlClick, onFileClick), + [mode, onUrlClick, onFileClick] + ) + + // Preprocess to convert raw URLs and file paths to markdown links + const processedContent = React.useMemo(() => preprocessLinks(children), [children]) + + return ( +
    + + {processedContent} + +
    + ) +} + +/** + * MemoizedMarkdown - Optimized for streaming scenarios + * + * Splits content into blocks and memoizes each block separately, + * so only new/changed blocks re-render during streaming. + */ +export const MemoizedMarkdown = React.memo(Markdown, (prevProps, nextProps) => { + // If id is provided, use it for memoization + if (prevProps.id && nextProps.id) { + return ( + prevProps.id === nextProps.id && + prevProps.children === nextProps.children && + prevProps.mode === nextProps.mode + ) + } + // Otherwise compare content and mode + return prevProps.children === nextProps.children && prevProps.mode === nextProps.mode +}) +MemoizedMarkdown.displayName = 'MemoizedMarkdown' diff --git a/packages/ui/src/components/markdown/StreamingMarkdown.tsx b/packages/ui/src/components/markdown/StreamingMarkdown.tsx new file mode 100644 index 00000000..6d68435f --- /dev/null +++ b/packages/ui/src/components/markdown/StreamingMarkdown.tsx @@ -0,0 +1,186 @@ +import * as React from 'react' +import { Markdown, type RenderMode } from './Markdown' + +export interface StreamingMarkdownProps { + content: string + isStreaming: boolean + mode?: RenderMode + onUrlClick?: (url: string) => void + onFileClick?: (path: string) => void +} + +interface Block { + content: string + isCodeBlock: boolean +} + +/** + * Simple hash function for cache keys + * Uses djb2 algorithm - fast and produces good distribution + */ +function simpleHash(str: string): string { + let hash = 5381 + for (let i = 0; i < str.length; i++) { + hash = ((hash << 5) + hash) ^ str.charCodeAt(i) + } + return (hash >>> 0).toString(36) +} + +/** + * Split content into blocks (paragraphs and code blocks) + * + * Block boundaries: + * - Double newlines (paragraph separators) + * - Code fences (```) + * + * This is intentionally simple - just string scanning, no regex per line. + */ +function splitIntoBlocks(content: string): Block[] { + const blocks: Block[] = [] + const lines = content.split('\n') + let currentBlock = '' + let inCodeBlock = false + + for (let i = 0; i < lines.length; i++) { + const line = lines[i] + + // Check for code fence (``` at start of line, optionally followed by language) + if (line.startsWith('```')) { + if (!inCodeBlock) { + // Starting a code block - flush current paragraph first + if (currentBlock.trim()) { + blocks.push({ content: currentBlock.trim(), isCodeBlock: false }) + currentBlock = '' + } + inCodeBlock = true + currentBlock = line + '\n' + } else { + // Ending a code block + currentBlock += line + blocks.push({ content: currentBlock, isCodeBlock: true }) + currentBlock = '' + inCodeBlock = false + } + } else if (inCodeBlock) { + // Inside code block - append line + currentBlock += line + '\n' + } else if (line === '') { + // Empty line outside code block = paragraph boundary + if (currentBlock.trim()) { + blocks.push({ content: currentBlock.trim(), isCodeBlock: false }) + currentBlock = '' + } + } else { + // Regular text line + if (currentBlock) { + currentBlock += '\n' + line + } else { + currentBlock = line + } + } + } + + // Flush remaining content + if (currentBlock) { + blocks.push({ + content: inCodeBlock ? currentBlock : currentBlock.trim(), + isCodeBlock: inCodeBlock // Unclosed code block = still streaming + }) + } + + return blocks +} + +/** + * Memoized block component + * + * Only re-renders if content or mode changes. + * The key is assigned by the parent based on content hash, + * so identical content won't even attempt to render. + */ +const MemoizedBlock = React.memo( + function Block({ + content, + mode, + onUrlClick, + onFileClick + }: { + content: string + mode: RenderMode + onUrlClick?: (url: string) => void + onFileClick?: (path: string) => void + }) { + return ( + + {content} + + ) + }, + (prev, next) => { + // Only re-render if content actually changed + return prev.content === next.content && prev.mode === next.mode + } +) +MemoizedBlock.displayName = 'MemoizedBlock' + +/** + * StreamingMarkdown - Optimized markdown renderer for streaming content + * + * Splits content into blocks (paragraphs, code blocks) and memoizes each block + * independently. Only the last (active) block re-renders during streaming. + * + * Key insight: Completed blocks get a content-hash as their React key. + * Same content = same key = React skips re-render entirely. + * + * @example + * Content: "Hello\n\n```js\ncode\n```\n\nMore..." + * + * Block 1: "Hello" -> key="block-abc123" -> memoized + * Block 2: "```js\ncode\n```" -> key="block-xyz789" -> memoized + * Block 3: "More..." -> key="active-2" -> re-renders + */ +export function StreamingMarkdown({ + content, + isStreaming, + mode = 'minimal', + onUrlClick, + onFileClick +}: StreamingMarkdownProps): React.JSX.Element { + // Split into blocks - memoized to avoid recomputation + // Must be called unconditionally to satisfy Rules of Hooks + const blocks = React.useMemo( + () => (isStreaming ? splitIntoBlocks(content) : []), + [content, isStreaming] + ) + + // Not streaming - use simple Markdown (no block splitting needed) + if (!isStreaming) { + return ( + + {content} + + ) + } + + return ( + <> + {blocks.map((block, i) => { + const isLastBlock = i === blocks.length - 1 + + // Complete blocks use content hash as key -> stable identity -> memoized + // Last block uses "active" prefix -> always re-renders on content change + const key = isLastBlock ? `active-${i}` : `block-${simpleHash(block.content)}` + + return ( + + ) + })} + + ) +} diff --git a/packages/ui/src/components/markdown/index.ts b/packages/ui/src/components/markdown/index.ts new file mode 100644 index 00000000..a2a89c50 --- /dev/null +++ b/packages/ui/src/components/markdown/index.ts @@ -0,0 +1,4 @@ +export { Markdown, MemoizedMarkdown, type MarkdownProps, type RenderMode } from './Markdown' +export { CodeBlock, InlineCode, type CodeBlockProps } from './CodeBlock' +export { StreamingMarkdown, type StreamingMarkdownProps } from './StreamingMarkdown' +export { preprocessLinks, detectLinks, hasLinks } from './linkify' diff --git a/packages/ui/src/components/markdown/linkify.ts b/packages/ui/src/components/markdown/linkify.ts new file mode 100644 index 00000000..ed06a9b7 --- /dev/null +++ b/packages/ui/src/components/markdown/linkify.ts @@ -0,0 +1,195 @@ +import LinkifyIt from 'linkify-it' + +/** + * Linkify - URL and file path detection for markdown preprocessing + * + * Uses linkify-it (12M downloads/week) for battle-tested URL detection, + * plus custom regex for local file paths. + */ + +// Initialize linkify-it with default settings (fuzzy URLs, emails enabled) +const linkify = new LinkifyIt() + +// File path regex - detects /path, ~/path, ./path with common extensions +// Matches paths that start with /, ~/, or ./ followed by path chars and a file extension +const FILE_PATH_REGEX = + /(?:^|[\s([{<])((\/|~\/|\.\/)[\w\-./@]+\.(?:ts|tsx|js|jsx|mjs|cjs|md|json|yaml|yml|py|go|rs|css|scss|less|html|htm|txt|log|sh|bash|zsh|swift|kt|java|c|cpp|h|hpp|rb|php|xml|toml|ini|cfg|conf|env|sql|graphql|vue|svelte|astro|prisma|dockerfile|makefile|gitignore))(?=[\s)\]}.,;:!?>]|$)/gi + +interface DetectedLink { + type: 'url' | 'email' | 'file' + text: string + url: string + start: number + end: number +} + +interface CodeRange { + start: number + end: number +} + +/** + * Find all code block and inline code ranges in text + * These ranges should be excluded from link detection + */ +function findCodeRanges(text: string): CodeRange[] { + const ranges: CodeRange[] = [] + + // Find fenced code blocks (```...```) + const fencedRegex = /```[\s\S]*?```/g + let match + while ((match = fencedRegex.exec(text)) !== null) { + ranges.push({ start: match.index, end: match.index + match[0].length }) + } + + // Find inline code (`...`) + // But skip escaped backticks and code inside fenced blocks + const inlineRegex = /(? pos >= r.start && pos < r.end) + if (!insideFenced) { + ranges.push({ start: pos, end: pos + match[0].length }) + } + } + + return ranges +} + +/** + * Check if a position is inside any code range + */ +function isInsideCode(pos: number, ranges: CodeRange[]): boolean { + return ranges.some((r) => pos >= r.start && pos < r.end) +} + +/** + * Check if a link at given position is already a markdown link + * Looks for patterns like [text](url) or [text][ref] + */ +function isAlreadyLinked(text: string, linkStart: number, linkEnd: number): boolean { + // Check if preceded by ]( which indicates we're inside a markdown link href + // Pattern: [text](URL) - we're checking if URL is our link + const before = text.slice(Math.max(0, linkStart - 2), linkStart) + if (before.endsWith('](')) return true + + // Check if preceded by ][ for reference links + if (before.endsWith('][')) return true + + // Check if the link text is wrapped in [] + // Pattern: [URL](href) - URL is being used as link text + const charBefore = text[linkStart - 1] + const charAfter = text[linkEnd] + if (charBefore === '[' && charAfter === ']') return true + + return false +} + +/** + * Check if ranges overlap + */ +function rangesOverlap( + a: { start: number; end: number }, + b: { start: number; end: number } +): boolean { + return a.start < b.end && b.start < a.end +} + +/** + * Detect all links (URLs, emails, file paths) in text + */ +export function detectLinks(text: string): DetectedLink[] { + const links: DetectedLink[] = [] + + // 1. Detect URLs and emails with linkify-it + const urlMatches = linkify.match(text) || [] + for (const match of urlMatches) { + links.push({ + type: match.schema === 'mailto:' ? 'email' : 'url', + text: match.text, + url: match.url, + start: match.index, + end: match.lastIndex + }) + } + + // 2. Detect file paths with custom regex + // Reset regex state + FILE_PATH_REGEX.lastIndex = 0 + let fileMatch + while ((fileMatch = FILE_PATH_REGEX.exec(text)) !== null) { + const path = fileMatch[1] + if (!path) continue // Skip if no capture group + + // Calculate actual start position (after any leading whitespace/punctuation) + const fullMatch = fileMatch[0] + const pathOffset = fullMatch.indexOf(path) + const start = fileMatch.index + pathOffset + + // Check for overlaps with URL matches (URLs take precedence) + const pathRange = { start, end: start + path.length } + const overlapsUrl = links.some((link) => rangesOverlap(pathRange, link)) + if (overlapsUrl) continue + + links.push({ + type: 'file', + text: path, + url: path, // File paths are passed as-is to onFileClick handler + start, + end: start + path.length + }) + } + + // Sort by position + return links.sort((a, b) => a.start - b.start) +} + +/** + * Preprocess text to convert raw URLs and file paths into markdown links + * Skips code blocks and already-linked content + */ +export function preprocessLinks(text: string): string { + // Quick check - if no potential links, return early + if (!linkify.pretest(text) && !/[~/.]\//.test(text)) { + return text + } + + const codeRanges = findCodeRanges(text) + const links = detectLinks(text) + + if (links.length === 0) return text + + // Build result, converting raw links to markdown links + let result = '' + let lastIndex = 0 + + for (const link of links) { + // Skip if inside code block + if (isInsideCode(link.start, codeRanges)) continue + + // Skip if already a markdown link + if (isAlreadyLinked(text, link.start, link.end)) continue + + // Add text before this link + result += text.slice(lastIndex, link.start) + + // Convert to markdown link + result += `[${link.text}](${link.url})` + + lastIndex = link.end + } + + // Add remaining text + result += text.slice(lastIndex) + + return result +} + +/** + * Test if text contains any detectable links + * Useful for optimization - skip preprocessing if no links present + */ +export function hasLinks(text: string): boolean { + return linkify.pretest(text) || /[~/.]\/[\w]/.test(text) +} diff --git a/packages/ui/src/styles/globals.css b/packages/ui/src/styles/globals.css index 98c7c9eb..3afc7312 100644 --- a/packages/ui/src/styles/globals.css +++ b/packages/ui/src/styles/globals.css @@ -119,6 +119,20 @@ --sidebar-ring: oklch(0.552 0.016 285.938); } +/* Shiki dual themes: CSS-only light/dark switching via CSS variables */ +/* @see https://shiki.style/guide/dual-themes */ +.shiki, +.shiki span { + color: var(--shiki-light); + background-color: var(--shiki-light-bg); +} + +.dark .shiki, +.dark .shiki span { + color: var(--shiki-dark) !important; + background-color: var(--shiki-dark-bg) !important; +} + @layer base { * { @apply border-border outline-ring/50; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c06ab117..907d0a42 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,13 +34,13 @@ importers: dependencies: '@mariozechner/pi-agent-core': specifier: ^0.50.3 - version: 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6) + version: 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76) '@mariozechner/pi-ai': specifier: ^0.50.3 - version: 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6) + version: 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76) '@mariozechner/pi-coding-agent': specifier: ^0.50.3 - version: 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6) + version: 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76) '@mozilla/readability': specifier: ^0.6.0 version: 0.6.0 @@ -283,15 +283,30 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + linkify-it: + specifier: ^5.0.0 + version: 5.0.0 react: specifier: 'catalog:' version: 19.2.3 react-dom: specifier: 'catalog:' version: 19.2.3(react@19.2.3) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.10)(react@19.2.3) + rehype-raw: + specifier: ^7.0.0 + version: 7.0.0 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 shadcn: specifier: ^3.7.0 version: 3.7.0(@types/node@25.0.10)(hono@4.11.7)(typescript@5.9.3) + shiki: + specifier: ^3.21.0 + version: 3.21.0 tailwind-merge: specifier: ^3.4.0 version: 3.4.0 @@ -305,6 +320,9 @@ importers: '@tailwindcss/postcss': specifier: ^4 version: 4.1.18 + '@types/linkify-it': + specifier: ^5.0.0 + version: 5.0.0 '@types/react': specifier: 'catalog:' version: 19.2.10 @@ -1734,6 +1752,27 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@shikijs/core@3.21.0': + resolution: {integrity: sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==} + + '@shikijs/engine-javascript@3.21.0': + resolution: {integrity: sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ==} + + '@shikijs/engine-oniguruma@3.21.0': + resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==} + + '@shikijs/langs@3.21.0': + resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==} + + '@shikijs/themes@3.21.0': + resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==} + + '@shikijs/types@3.21.0': + resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@silvia-odwyer/photon-node@0.3.4': resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} @@ -2093,12 +2132,18 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/http-cache-semantics@4.2.0': resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} @@ -2111,6 +2156,12 @@ packages: '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/mime-types@2.1.4': resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} @@ -2143,6 +2194,12 @@ packages: '@types/turndown@5.0.6': resolution: {integrity: sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/uuid@11.0.0': resolution: {integrity: sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA==} deprecated: This is a stub types definition. uuid provides its own type definitions, so you do not need this installed. @@ -2615,6 +2672,9 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2736,6 +2796,9 @@ packages: caniuse-lite@1.0.30001766: resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -2748,6 +2811,18 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -2817,6 +2892,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2974,6 +3052,9 @@ packages: supports-color: optional: true + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -3029,6 +3110,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -3036,6 +3121,9 @@ packages: detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diff@8.0.3: resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} engines: {node: '>=0.3.1'} @@ -3164,6 +3252,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -3237,6 +3329,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} engines: {node: '>=6.0'} @@ -3384,6 +3480,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -3760,6 +3859,30 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + headers-polyfill@4.0.3: resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} @@ -3789,6 +3912,12 @@ packages: html-escaper@3.0.3: resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} @@ -3866,6 +3995,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -3878,6 +4010,12 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -3920,6 +4058,9 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3945,6 +4086,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-in-ssh@1.0.0: resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} engines: {node: '>=20'} @@ -4295,6 +4439,9 @@ packages: canvas: optional: true + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + load-esm@1.0.3: resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} engines: {node: '>=13.2.0'} @@ -4328,6 +4475,9 @@ packages: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -4364,6 +4514,9 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@15.0.12: resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} engines: {node: '>= 18'} @@ -4377,6 +4530,51 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -4396,6 +4594,90 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -4655,6 +4937,12 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + + oniguruma-to-es@4.3.4: + resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + open@11.0.0: resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} engines: {node: '>=20'} @@ -4716,6 +5004,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -4733,6 +5024,9 @@ packages: parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4874,6 +5168,9 @@ packages: proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4922,6 +5219,12 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -4959,10 +5262,34 @@ packages: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -5136,6 +5463,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shiki@3.21.0: + resolution: {integrity: sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -5218,6 +5548,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -5298,6 +5631,9 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + stringify-object@5.0.0: resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} engines: {node: '>=14.16'} @@ -5337,6 +5673,12 @@ packages: resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} engines: {node: '>=18'} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -5453,6 +5795,12 @@ packages: resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} engines: {node: '>=16'} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} @@ -5584,6 +5932,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + uhyphen@0.2.0: resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} @@ -5613,6 +5964,24 @@ packages: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -5667,6 +6036,15 @@ packages: resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} engines: {node: '>=0.6.0'} + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite-plugin-electron-renderer@0.14.6: resolution: {integrity: sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw==} @@ -5783,6 +6161,9 @@ packages: jsdom: optional: true + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -5950,6 +6331,9 @@ packages: use-sync-external-store: optional: true + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: 7zip-bin@5.2.0: {} @@ -5963,11 +6347,11 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.2 - '@anthropic-ai/sdk@0.71.2(zod@4.3.6)': + '@anthropic-ai/sdk@0.71.2(zod@3.25.76)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: - zod: 4.3.6 + zod: 3.25.76 '@aws-crypto/crc32@5.2.0': dependencies: @@ -6990,12 +7374,12 @@ snapshots: '@floating-ui/utils@0.2.10': {} - '@google/genai@1.34.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))': + '@google/genai@1.34.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))': dependencies: google-auth-library: 10.5.0 ws: 8.18.3 optionalDependencies: - '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.7)(zod@4.3.6) + '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.7)(zod@3.25.76) transitivePeerDependencies: - bufferutil - supports-color @@ -7250,9 +7634,9 @@ snapshots: std-env: 3.10.0 yoctocolors: 2.1.2 - '@mariozechner/pi-agent-core@0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6)': + '@mariozechner/pi-agent-core@0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76)': dependencies: - '@mariozechner/pi-ai': 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6) + '@mariozechner/pi-ai': 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76) '@mariozechner/pi-tui': 0.50.3 transitivePeerDependencies: - '@modelcontextprotocol/sdk' @@ -7263,21 +7647,21 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6)': + '@mariozechner/pi-ai@0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76)': dependencies: - '@anthropic-ai/sdk': 0.71.2(zod@4.3.6) + '@anthropic-ai/sdk': 0.71.2(zod@3.25.76) '@aws-sdk/client-bedrock-runtime': 3.978.0 - '@google/genai': 1.34.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6)) + '@google/genai': 1.34.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76)) '@mistralai/mistralai': 1.10.0 '@sinclair/typebox': 0.34.48 ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) chalk: 5.6.2 - openai: 6.10.0(ws@8.18.3)(zod@4.3.6) + openai: 6.10.0(ws@8.18.3)(zod@3.25.76) partial-json: 0.1.7 proxy-agent: 6.5.0 undici: 7.19.2 - zod-to-json-schema: 3.25.1(zod@4.3.6) + zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -7287,12 +7671,12 @@ snapshots: - ws - zod - '@mariozechner/pi-coding-agent@0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6)': + '@mariozechner/pi-coding-agent@0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76)': dependencies: '@mariozechner/clipboard': 0.3.0 '@mariozechner/jiti': 2.6.5 - '@mariozechner/pi-agent-core': 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6) - '@mariozechner/pi-ai': 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6))(ws@8.18.3)(zod@4.3.6) + '@mariozechner/pi-agent-core': 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76) + '@mariozechner/pi-ai': 0.50.3(@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76))(ws@8.18.3)(zod@3.25.76) '@mariozechner/pi-tui': 0.50.3 '@silvia-odwyer/photon-node': 0.3.4 chalk: 5.6.2 @@ -7350,29 +7734,6 @@ snapshots: - hono - supports-color - '@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.3.6)': - dependencies: - '@hono/node-server': 1.19.9(hono@4.11.7) - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - content-type: 1.0.5 - cors: 2.8.6 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.0.6 - express: 5.2.1 - express-rate-limit: 7.5.1(express@5.2.1) - jose: 6.1.3 - json-schema-typed: 8.0.2 - pkce-challenge: 5.0.1 - raw-body: 3.0.2 - zod: 4.3.6 - zod-to-json-schema: 3.25.1(zod@4.3.6) - transitivePeerDependencies: - - hono - - supports-color - optional: true - '@mozilla/readability@0.6.0': {} '@mswjs/interceptors@0.40.0': @@ -7613,6 +7974,39 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@shikijs/core@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + + '@shikijs/engine-oniguruma@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + + '@shikijs/themes@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + + '@shikijs/types@3.21.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + '@silvia-odwyer/photon-node@0.3.4': {} '@sinclair/typebox@0.34.48': {} @@ -8080,12 +8474,20 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + '@types/estree@1.0.8': {} '@types/fs-extra@9.0.13': dependencies: '@types/node': 25.0.10 + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/http-cache-semantics@4.2.0': {} '@types/json-schema@7.0.15': {} @@ -8096,6 +8498,12 @@ snapshots: dependencies: '@types/node': 25.0.10 + '@types/linkify-it@5.0.0': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/mime-types@2.1.4': {} '@types/ms@2.1.0': {} @@ -8130,6 +8538,10 @@ snapshots: '@types/turndown@5.0.6': {} + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@types/uuid@11.0.0': dependencies: uuid: 13.0.0 @@ -8696,6 +9108,8 @@ snapshots: axobject-query@4.1.0: {} + bail@2.0.2: {} + balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -8846,6 +9260,8 @@ snapshots: caniuse-lite@1.0.30001766: {} + ccount@2.0.1: {} + chai@6.2.2: {} chalk@4.1.2: @@ -8855,6 +9271,14 @@ snapshots: chalk@5.6.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chownr@2.0.0: {} chromium-pickle-js@0.2.0: {} @@ -8922,6 +9346,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@11.1.0: {} commander@14.0.2: {} @@ -9057,6 +9483,10 @@ snapshots: dependencies: ms: 2.1.3 + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -9100,11 +9530,17 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + detect-libc@2.1.2: {} detect-node@2.1.0: optional: true + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + diff@8.0.3: {} dir-compare@3.3.0: @@ -9297,6 +9733,8 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + entities@7.0.1: {} env-paths@2.2.1: {} @@ -9474,6 +9912,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + escodegen@2.1.0: dependencies: esprima: 4.0.1 @@ -9488,7 +9928,7 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1)) @@ -9521,7 +9961,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -9536,7 +9976,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -9747,6 +10187,8 @@ snapshots: estraverse@5.3.0: {} + estree-util-is-identifier-name@3.0.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -10233,6 +10675,93 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + headers-polyfill@4.0.3: {} help-me@5.0.0: {} @@ -10255,6 +10784,10 @@ snapshots: html-escaper@3.0.3: {} + html-url-attributes@3.0.1: {} + + html-void-elements@3.0.0: {} + htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 @@ -10344,6 +10877,8 @@ snapshots: inherits@2.0.4: {} + inline-style-parser@0.2.7: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -10354,6 +10889,13 @@ snapshots: ipaddr.js@1.9.1: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -10404,6 +10946,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-decimal@2.0.1: {} + is-docker@3.0.0: {} is-extglob@2.1.1: {} @@ -10426,6 +10970,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-in-ssh@1.0.0: {} is-inside-container@1.0.0: @@ -10718,6 +11264,10 @@ snapshots: htmlparser2: 10.1.0 uhyphen: 0.2.0 + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + load-esm@1.0.3: {} locate-path@6.0.0: @@ -10743,6 +11293,8 @@ snapshots: chalk: 5.6.2 is-unicode-supported: 1.3.0 + longest-streak@3.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -10777,6 +11329,8 @@ snapshots: dependencies: semver: 7.7.3 + markdown-table@3.0.4: {} + marked@15.0.12: {} matcher@3.0.0: @@ -10786,6 +11340,159 @@ snapshots: math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.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.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + media-typer@0.3.0: {} media-typer@1.1.0: {} @@ -10796,6 +11503,197 @@ snapshots: merge2@1.4.1: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -11044,6 +11942,14 @@ snapshots: dependencies: mimic-function: 5.0.1 + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.4: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.1.0 + regex-recursion: 6.0.2 + open@11.0.0: dependencies: default-browser: 5.4.0 @@ -11053,10 +11959,10 @@ snapshots: powershell-utils: 0.1.0 wsl-utils: 0.3.1 - openai@6.10.0(ws@8.18.3)(zod@4.3.6): + openai@6.10.0(ws@8.18.3)(zod@3.25.76): optionalDependencies: ws: 8.18.3 - zod: 4.3.6 + zod: 3.25.76 optionator@0.9.4: dependencies: @@ -11123,6 +12029,16 @@ snapshots: dependencies: callsites: 3.1.0 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.28.6 @@ -11140,6 +12056,10 @@ snapshots: parse5@6.0.1: {} + parse5@7.3.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} partial-json@0.1.7: {} @@ -11288,6 +12208,8 @@ snapshots: retry: 0.12.0 signal-exit: 3.0.7 + property-information@7.1.0: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -11341,6 +12263,24 @@ snapshots: react-is@16.13.1: {} + react-markdown@10.1.0(@types/react@19.2.10)(react@19.2.3): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.2.10 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.3 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + react-refresh@0.17.0: {} react@19.2.3: {} @@ -11397,6 +12337,16 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 @@ -11406,6 +12356,46 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -11694,6 +12684,17 @@ snapshots: shebang-regex@3.0.0: {} + shiki@3.21.0: + dependencies: + '@shikijs/core': 3.21.0 + '@shikijs/engine-javascript': 3.21.0 + '@shikijs/engine-oniguruma': 3.21.0 + '@shikijs/langs': 3.21.0 + '@shikijs/themes': 3.21.0 + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -11812,6 +12813,8 @@ snapshots: source-map@0.6.1: {} + space-separated-tokens@2.0.2: {} + split2@4.2.0: {} sprintf-js@1.1.3: @@ -11914,6 +12917,11 @@ snapshots: dependencies: safe-buffer: 5.2.1 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + stringify-object@5.0.0: dependencies: get-own-enumerable-keys: 1.0.0 @@ -11944,6 +12952,14 @@ snapshots: dependencies: '@tokenizer/token': 0.3.0 + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + styled-jsx@5.1.6(react@19.2.3): dependencies: client-only: 0.0.1 @@ -12048,6 +13064,10 @@ snapshots: dependencies: tldts: 7.0.19 + trim-lines@3.0.1: {} + + trough@2.2.0: {} + truncate-utf8-bytes@1.0.2: dependencies: utf8-byte-length: 1.0.5 @@ -12194,6 +13214,8 @@ snapshots: typescript@5.9.3: {} + uc.micro@2.1.0: {} + uhyphen@0.2.0: {} uid@2.0.2: @@ -12217,6 +13239,39 @@ snapshots: unicorn-magic@0.3.0: {} + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + universalify@0.1.2: {} universalify@2.0.1: {} @@ -12280,6 +13335,21 @@ snapshots: extsprintf: 1.4.1 optional: true + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + vite-plugin-electron-renderer@0.14.6: {} vite-plugin-electron@0.28.8(vite-plugin-electron-renderer@0.14.6): @@ -12349,6 +13419,8 @@ snapshots: - tsx - yaml + web-namespaces@2.0.1: {} + web-streams-polyfill@3.3.3: {} which-boxed-primitive@1.1.1: @@ -12493,10 +13565,6 @@ snapshots: dependencies: zod: 3.25.76 - zod-to-json-schema@3.25.1(zod@4.3.6): - dependencies: - zod: 4.3.6 - zod-validation-error@4.0.2(zod@4.3.6): dependencies: zod: 4.3.6 @@ -12510,3 +13578,5 @@ snapshots: '@types/react': 19.2.10 react: 19.2.3 use-sync-external-store: 1.6.0(react@19.2.3) + + zwitch@2.0.4: {}