diff --git a/apps/x/packages/core/package.json b/apps/x/packages/core/package.json index 3e162a02..2633e4d0 100644 --- a/apps/x/packages/core/package.json +++ b/apps/x/packages/core/package.json @@ -17,6 +17,8 @@ "@google-cloud/local-auth": "^3.0.1", "@modelcontextprotocol/sdk": "^1.25.1", "@openrouter/ai-sdk-provider": "^1.2.6", + "@react-pdf/renderer": "^4.3.2", + "@types/react": "^19.2.7", "@x/shared": "workspace:*", "ai": "^5.0.102", "awilix": "^12.0.5", @@ -27,6 +29,7 @@ "node-html-markdown": "^2.0.0", "ollama-ai-provider-v2": "^1.5.4", "openid-client": "^6.8.1", + "react": "^19.2.3", "yaml": "^2.8.2", "zod": "^4.2.1" }, diff --git a/apps/x/packages/core/src/application/assistant/instructions.ts b/apps/x/packages/core/src/application/assistant/instructions.ts index 3814064e..d70ef66a 100644 --- a/apps/x/packages/core/src/application/assistant/instructions.ts +++ b/apps/x/packages/core/src/application/assistant/instructions.ts @@ -26,6 +26,8 @@ Rowboat is an agentic assistant for everyday work - emails, meetings, projects, **Meeting Prep:** When users ask you to prepare for a meeting, prep for a call, or brief them on attendees, load the \`meeting-prep\` skill first. It provides structured guidance for gathering context about attendees from the knowledge base and creating useful meeting briefs. +**Create Presentations:** When users ask you to create a presentation, slide deck, pitch deck, or PDF slides, load the \`create-presentations\` skill first. It provides structured guidance for generating PDF presentations using context from the knowledge base. + **Document Collaboration:** When users ask you to work on a document, collaborate on writing, create a new document, edit/refine existing notes, or say things like "let's work on [X]", "help me write [X]", "create a doc for [X]", or "let's draft [X]", you MUST load the \`doc-collab\` skill first. This is required for any document creation or editing task. The skill provides structured guidance for creating, editing, and refining documents in the knowledge base. ## Memory That Compounds diff --git a/apps/x/packages/core/src/application/assistant/skills/create-presentations/presentation-generator.tsx b/apps/x/packages/core/src/application/assistant/skills/create-presentations/presentation-generator.tsx new file mode 100644 index 00000000..ffeef70e --- /dev/null +++ b/apps/x/packages/core/src/application/assistant/skills/create-presentations/presentation-generator.tsx @@ -0,0 +1,446 @@ +import React from 'react'; +import { + Document, + Page, + Text, + View, + Image, + StyleSheet, + renderToFile, +} from '@react-pdf/renderer'; +import type { Slide, Theme, PresentationData, TitleSlide, ContentSlide, SectionSlide, StatsSlide, TwoColumnSlide, QuoteSlide, ImageSlide, TeamSlide, CTASlide } from './types.js'; + +const defaultTheme: Theme = { + primaryColor: '#6366f1', + secondaryColor: '#8b5cf6', + accentColor: '#f59e0b', + textColor: '#1f2937', + textLight: '#6b7280', + background: '#ffffff', + backgroundAlt: '#f9fafb', + fontFamily: 'Helvetica', +}; + +const SLIDE_WIDTH = 1280; +const SLIDE_HEIGHT = 720; + +const createStyles = (theme: Theme) => + StyleSheet.create({ + slide: { + width: SLIDE_WIDTH, + height: SLIDE_HEIGHT, + padding: 60, + backgroundColor: theme.background, + position: 'relative', + }, + slideAlt: { + backgroundColor: theme.backgroundAlt, + }, + slideGradient: { + backgroundColor: theme.primaryColor, + }, + pageNumber: { + position: 'absolute', + bottom: 30, + right: 40, + fontSize: 14, + color: theme.textLight, + }, + slideTitle: { + fontSize: 42, + fontWeight: 'bold', + color: theme.textColor, + marginBottom: 30, + }, + slideBody: { + fontSize: 24, + color: theme.textColor, + lineHeight: 1.6, + }, + titleSlide: { + justifyContent: 'center' as const, + alignItems: 'center' as const, + }, + mainTitle: { + fontSize: 64, + fontWeight: 'bold', + color: '#ffffff', + textAlign: 'center' as const, + marginBottom: 20, + }, + mainSubtitle: { + fontSize: 28, + color: 'rgba(255, 255, 255, 0.9)', + textAlign: 'center' as const, + marginBottom: 30, + }, + presenter: { + fontSize: 20, + color: 'rgba(255, 255, 255, 0.8)', + textAlign: 'center' as const, + }, + titleDecoration: { + position: 'absolute' as const, + bottom: 0, + left: 0, + right: 0, + height: 8, + backgroundColor: theme.accentColor, + }, + sectionNumber: { + fontSize: 80, + fontWeight: 'bold', + color: theme.primaryColor, + opacity: 0.2, + marginBottom: -20, + }, + sectionTitle: { + fontSize: 56, + fontWeight: 'bold', + color: theme.textColor, + }, + sectionSubtitle: { + fontSize: 24, + color: theme.textLight, + marginTop: 15, + }, + contentList: { + marginTop: 10, + }, + listItem: { + flexDirection: 'row' as const, + marginBottom: 16, + alignItems: 'flex-start' as const, + }, + listBullet: { + width: 12, + height: 12, + borderRadius: 6, + backgroundColor: theme.primaryColor, + marginRight: 20, + marginTop: 8, + }, + listText: { + flex: 1, + fontSize: 24, + color: theme.textColor, + lineHeight: 1.5, + }, + columnsContainer: { + flexDirection: 'row' as const, + flex: 1, + gap: 60, + }, + column: { + flex: 1, + }, + columnTitle: { + fontSize: 24, + fontWeight: 'bold', + color: theme.primaryColor, + marginBottom: 15, + }, + statsGrid: { + flexDirection: 'row' as const, + justifyContent: 'space-around' as const, + alignItems: 'center' as const, + flex: 1, + }, + statItem: { + alignItems: 'center' as const, + padding: 30, + }, + statValue: { + fontSize: 72, + fontWeight: 'bold', + color: theme.primaryColor, + marginBottom: 10, + }, + statLabel: { + fontSize: 20, + color: theme.textLight, + textTransform: 'uppercase' as const, + letterSpacing: 1, + }, + statsNote: { + textAlign: 'center' as const, + fontSize: 18, + color: theme.textLight, + marginTop: 20, + }, + quoteSlide: { + justifyContent: 'center' as const, + alignItems: 'center' as const, + }, + quoteText: { + fontSize: 36, + fontStyle: 'italic', + color: theme.textColor, + textAlign: 'center' as const, + maxWidth: 900, + lineHeight: 1.5, + }, + quoteAttribution: { + fontSize: 20, + color: theme.textLight, + marginTop: 30, + textAlign: 'center' as const, + }, + imageContainer: { + flex: 1, + justifyContent: 'center' as const, + alignItems: 'center' as const, + marginVertical: 20, + }, + slideImage: { + maxWidth: '100%', + maxHeight: 450, + objectFit: 'contain' as const, + }, + imageCaption: { + textAlign: 'center' as const, + fontSize: 18, + color: theme.textLight, + }, + teamGrid: { + flexDirection: 'row' as const, + justifyContent: 'center' as const, + gap: 50, + flex: 1, + alignItems: 'center' as const, + }, + teamMember: { + alignItems: 'center' as const, + maxWidth: 200, + }, + memberPhotoPlaceholder: { + width: 120, + height: 120, + borderRadius: 60, + backgroundColor: theme.primaryColor, + marginBottom: 15, + }, + memberPhoto: { + width: 120, + height: 120, + borderRadius: 60, + marginBottom: 15, + }, + memberName: { + fontSize: 20, + fontWeight: 'bold', + color: theme.textColor, + textAlign: 'center' as const, + }, + memberRole: { + fontSize: 16, + color: theme.primaryColor, + marginTop: 5, + textAlign: 'center' as const, + }, + memberBio: { + fontSize: 14, + color: theme.textLight, + marginTop: 10, + textAlign: 'center' as const, + lineHeight: 1.4, + }, + ctaSlide: { + justifyContent: 'center' as const, + alignItems: 'center' as const, + }, + ctaTitle: { + fontSize: 56, + fontWeight: 'bold', + color: '#ffffff', + textAlign: 'center' as const, + marginBottom: 20, + }, + ctaSubtitle: { + fontSize: 24, + color: 'rgba(255, 255, 255, 0.9)', + textAlign: 'center' as const, + marginBottom: 40, + }, + ctaContact: { + fontSize: 20, + color: 'rgba(255, 255, 255, 0.8)', + textAlign: 'center' as const, + }, + }); + +type Styles = ReturnType; + +const TitleSlideComponent: React.FC<{ slide: TitleSlide; styles: Styles }> = ({ slide, styles }) => ( + + {slide.title} + {slide.subtitle && {slide.subtitle}} + {slide.presenter && {slide.presenter}} + + +); + +const SectionSlideComponent: React.FC<{ slide: SectionSlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + + {String(pageNum).padStart(2, '0')} + {slide.title} + {slide.subtitle && {slide.subtitle}} + + {pageNum} + +); + +const ContentSlideComponent: React.FC<{ slide: ContentSlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + {slide.title} + {slide.content && {slide.content}} + {slide.items && ( + + {slide.items.map((item, i) => ( + + + {item} + + ))} + + )} + {pageNum} + +); + +const TwoColumnSlideComponent: React.FC<{ slide: TwoColumnSlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + {slide.title} + + {slide.columns.map((col, i) => ( + + {col.title && {col.title}} + {col.content && {col.content}} + {col.items && ( + + {col.items.map((item, j) => ( + + + {item} + + ))} + + )} + + ))} + + {pageNum} + +); + +const StatsSlideComponent: React.FC<{ slide: StatsSlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + {slide.title} + + {slide.stats.map((stat, i) => ( + + {stat.value} + {stat.label} + + ))} + + {slide.note && {slide.note}} + {pageNum} + +); + +const QuoteSlideComponent: React.FC<{ slide: QuoteSlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + "{slide.quote}" + {slide.attribution && — {slide.attribution}} + {pageNum} + +); + +const ImageSlideComponent: React.FC<{ slide: ImageSlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + {slide.title} + + + + {slide.caption && {slide.caption}} + {pageNum} + +); + +const TeamSlideComponent: React.FC<{ slide: TeamSlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + {slide.title} + + {slide.members.map((member, i) => ( + + {member.photoPath ? ( + + ) : ( + + )} + {member.name} + {member.role} + {member.bio && {member.bio}} + + ))} + + {pageNum} + +); + +const CTASlideComponent: React.FC<{ slide: CTASlide; pageNum: number; styles: Styles }> = ({ slide, pageNum, styles }) => ( + + {slide.title} + {slide.subtitle && {slide.subtitle}} + {slide.contact && {slide.contact}} + {pageNum} + +); + +const renderSlide = ( + slide: Slide, + index: number, + styles: Styles +): React.ReactElement => { + const pageNum = index + 1; + + switch (slide.type) { + case 'title': + return ; + case 'section': + return ; + case 'content': + return ; + case 'two-column': + return ; + case 'stats': + return ; + case 'quote': + return ; + case 'image': + return ; + case 'team': + return ; + case 'cta': + return ; + default: + return ; + } +}; + +const Presentation: React.FC = ({ slides, theme }) => { + const mergedTheme = { ...defaultTheme, ...theme }; + const styles = createStyles(mergedTheme); + + return {slides.map((slide, i) => renderSlide(slide, i, styles))}; +}; + +export async function generatePresentation( + data: PresentationData, + outputPath: string +): Promise { + await renderToFile(, outputPath); + return outputPath; +} diff --git a/apps/x/packages/core/src/application/assistant/skills/create-presentations/skill.ts b/apps/x/packages/core/src/application/assistant/skills/create-presentations/skill.ts new file mode 100644 index 00000000..467bc057 --- /dev/null +++ b/apps/x/packages/core/src/application/assistant/skills/create-presentations/skill.ts @@ -0,0 +1,367 @@ +export const skill = String.raw` +# PDF Presentation Generator Skill + +## Overview + +This skill enables Rowboat to create stunning PDF presentations from natural language requests. Use the built-in **generatePresentation** tool to render slides to PDF. + +## When to Use This Skill + +Activate this skill when the user requests: +- Creating presentations, slide decks, or pitch decks +- Making PDF slides for meetings, talks, or pitches +- Generating visual summaries or reports in presentation format +- Keywords: "presentation", "slides", "deck", "pitch deck", "slide deck", "PDF presentation" + +## Knowledge Sources + +Before creating any presentation, gather context from the user's knowledge base: + +~~~ +~/.rowboat/knowledge/ +├── company/ +│ ├── about.md # Company description, mission, vision +│ ├── team.md # Founder bios, team members +│ ├── metrics.md # KPIs, growth numbers, financials +│ ├── product.md # Product description, features, roadmap +│ └── branding.md # Colors, fonts, logo paths, style guide +├── fundraising/ +│ ├── previous-rounds.md # Past funding history +│ ├── investors.md # Current investors, target investors +│ ├── use-of-funds.md # How funds will be allocated +│ └── projections.md # Financial projections +├── market/ +│ ├── problem.md # Problem statement +│ ├── solution.md # How product solves it +│ ├── competitors.md # Competitive landscape +│ ├── tam-sam-som.md # Market size analysis +│ └── traction.md # Customer testimonials, case studies +└── assets/ + ├── logo.png # Company logo + ├── product-screenshots/ + └── team-photos/ +~~~ + +**Important:** Always check for and read relevant files from ~/.rowboat/knowledge/ before generating content. If files don't exist, ask the user for the information and offer to save it for future use. + +## Workflow + +### Step 1: Understand the Request & Gather Preferences + +Before doing anything else, ask the user about their preferences: + +1. **Content density**: Should the slides be text-heavy with detailed explanations, or minimal with just key points and big numbers? +2. **Color / theme**: Do they have brand colors or a color preference? (e.g., "use our brand blue #2563eb" or "dark theme" or "keep it default") +3. **Presentation type**: pitch deck, product demo, team intro, investor update, etc. +4. **Audience**: investors, customers, internal team, conference +5. **Tone**: formal, casual, technical, inspirational +6. **Length**: number of slides (default: 10-12 for pitch decks) + +Ask these as a concise set of questions in a single message. Use any answers the user already provided in their initial request and only ask about what's missing. + +### Step 2: Gather Knowledge + +~~~bash +# Check what knowledge exists +ls -la ~/.rowboat/knowledge/ 2>/dev/null || echo "No knowledge directory found" + +# Read relevant files based on presentation type +# For a pitch deck, prioritize: +cat ~/.rowboat/knowledge/company/about.md 2>/dev/null +cat ~/.rowboat/knowledge/market/problem.md 2>/dev/null +cat ~/.rowboat/knowledge/company/metrics.md 2>/dev/null +cat ~/.rowboat/knowledge/company/branding.md 2>/dev/null +~~~ + +### Step 3: Present the Outline for Approval + +Before generating slides, present a structured outline to the user: + +~~~ +## Proposed Presentation Outline + +**Title:** [Presentation Title] +**Slides:** [N] slides +**Estimated read time:** [X] minutes + +### Flow: + +1. **Title Slide** + - Company name, tagline, presenter name + +2. **Problem** + - [One sentence summary of the problem] + +3. **Solution** + - [One sentence summary of your solution] + +... + +--- + +Does this look good? I can adjust the outline, then I'll go ahead and generate the PDF for you. +- Add/remove slides +- Reorder sections +- Adjust emphasis on any area +~~~ + +After the user approves (or after incorporating their feedback), immediately ask: **"I'll generate the PDF now — where should I save it?"** If the user has already indicated a path or preference, skip asking and generate directly. + +**IMPORTANT:** Always generate the PDF. Never suggest the user copy content into Keynote, Google Slides, or any other tool. The whole point of this skill is to produce a finished PDF. + +### Step 4: Generate the Presentation + +Once approved, call the **generatePresentation** tool with the slides JSON and output path. Apply the user's theme/color preferences from Step 1. + +## Slide Types Reference + +| Type | Description | Required Fields | +|------|-------------|-----------------| +| title | Opening slide with gradient background | title | +| section | Section divider with large number | title | +| content | Standard content slide | title, content or items | +| two-column | Two column layout | title, columns (array of 2) | +| stats | Big numbers display | title, stats (array of {value, label}) | +| quote | Testimonial/quote | quote | +| image | Image with caption | title, imagePath | +| team | Team member grid | title, members (array) | +| cta | Call to action / closing | title | + +## Slide Type Details + +### title +~~~json +{ + "type": "title", + "title": "Company Name", + "subtitle": "Tagline or description", + "presenter": "Name • Context • Date" +} +~~~ + +### content +~~~json +{ + "type": "content", + "title": "Slide Title", + "content": "Optional paragraph text", + "items": ["Bullet point 1", "Bullet point 2", "Bullet point 3"] +} +~~~ + +### section +~~~json +{ + "type": "section", + "title": "Section Title", + "subtitle": "Optional subtitle" +} +~~~ + +### stats +~~~json +{ + "type": "stats", + "title": "Key Metrics", + "stats": [ + { "value": "$5M", "label": "Revenue" }, + { "value": "150%", "label": "YoY Growth" }, + { "value": "10K+", "label": "Users" } + ], + "note": "Optional footnote" +} +~~~ + +### two-column +~~~json +{ + "type": "two-column", + "title": "Comparison", + "columns": [ + { + "title": "Column A", + "content": "Optional text", + "items": ["Item 1", "Item 2"] + }, + { + "title": "Column B", + "content": "Optional text", + "items": ["Item 1", "Item 2"] + } + ] +} +~~~ + +### quote +~~~json +{ + "type": "quote", + "quote": "The quote text goes here.", + "attribution": "Person Name, Title" +} +~~~ + +### image +~~~json +{ + "type": "image", + "title": "Product Screenshot", + "imagePath": "/absolute/path/to/image.png", + "caption": "Optional caption" +} +~~~ + +### team +~~~json +{ + "type": "team", + "title": "Our Team", + "members": [ + { + "name": "Jane Doe", + "role": "CEO", + "bio": "Optional short bio", + "photoPath": "/absolute/path/to/photo.png" + } + ] +} +~~~ + +### cta +~~~json +{ + "type": "cta", + "title": "Let's Build Together", + "subtitle": "email@company.com", + "contact": "website.com • github.com/org" +} +~~~ + +## Theme Customization + +Pass an optional theme object to customize colors: + +~~~json +{ + "primaryColor": "#2563eb", + "secondaryColor": "#7c3aed", + "accentColor": "#f59e0b", + "textColor": "#1f2937", + "textLight": "#6b7280", + "background": "#ffffff", + "backgroundAlt": "#f9fafb", + "fontFamily": "Helvetica" +} +~~~ + +All theme fields are optional — defaults are used for any omitted fields. + +## Example: Calling generatePresentation + +~~~json +{ + "slides": [ + { + "type": "title", + "title": "Acme Corp", + "subtitle": "Revolutionizing Widget Manufacturing", + "presenter": "Jane Doe • Series A • 2025" + }, + { + "type": "content", + "title": "The Problem", + "items": [ + "Widget production is slow and expensive", + "Legacy systems can't keep up with demand", + "Quality control remains manual" + ] + }, + { + "type": "stats", + "title": "Traction", + "stats": [ + { "value": "500+", "label": "Customers" }, + { "value": "$2M", "label": "ARR" }, + { "value": "3x", "label": "YoY Growth" } + ] + }, + { + "type": "cta", + "title": "Let's Talk", + "subtitle": "jane@acme.com", + "contact": "acme.com" + } + ], + "theme": { + "primaryColor": "#2563eb" + }, + "outputPath": "/Users/user/Desktop/acme_pitch.pdf" +} +~~~ + +## Pitch Deck Templates + +### Series A Pitch Deck (12 slides) + +Standard flow for investor presentations: + +1. **Title** (type: title) - Company name, tagline, presenter +2. **Problem** (type: content) - What pain point you solve +3. **Solution** (type: content) - Your product/service +4. **Product** (type: image) - Demo/screenshots +5. **Market** (type: stats) - TAM/SAM/SOM +6. **Business Model** (type: content) - How you make money +7. **Traction** (type: stats) - Metrics and growth +8. **Competition** (type: two-column) - Your differentiation +9. **Team** (type: team) - Key team members +10. **Financials** (type: content or stats) - Projections +11. **The Ask** (type: content) - Funding amount and use +12. **Contact** (type: cta) - CTA with contact info + +### Product Demo Deck (8 slides) + +1. **Title** - Product name and tagline +2. **Problem** - User pain points +3. **Solution** - High-level approach +4. **Features** - Key capabilities (two-column) +5. **Demo** - Screenshots (image) +6. **Pricing** - Plans and pricing +7. **Testimonials** - Customer quotes (quote) +8. **Get Started** - CTA + +## Content Limits Per Slide (IMPORTANT) + +Each slide is a fixed 1280x720 page. Content that exceeds the available space will be clipped. Follow these limits strictly: + +| Slide Type | Max Items / Content | +|------------|-------------------| +| content | 5 bullet points max (keep each bullet to 1 line, ~80 chars). If using paragraph text instead, max ~4 lines. | +| two-column | 4 bullet points per column max. Keep bullets short (~60 chars). | +| stats | 3-4 stats max. Keep labels short (1-2 words). | +| team | 4 members max per slide. Split into multiple team slides if needed. | +| quote | Keep quotes under ~200 characters. | +| image | Caption should be 1 line. | + +**If the user's content needs more space**, split it across multiple slides of the same type rather than cramming it into one. For example, if there are 8 bullet points, use two content slides (4 each) with titles like "Key Benefits (1/2)" and "Key Benefits (2/2)". + +## Best Practices + +1. **Keep slides simple** - One idea per slide +2. **Use stats slides for numbers** - Big, bold metrics +3. **Limit bullet points** - 3-5 max per slide, keep them short +4. **Use two-column for comparisons** - Us vs. them, before/after +5. **End with clear CTA** - What do you want them to do? +6. **Gather knowledge first** - Check ~/.rowboat/knowledge/ before generating +7. **Use absolute paths** for images (PNG, JPG supported) +8. **Never overflow** - If content doesn't fit, split across multiple slides + +## Output + +The generatePresentation tool produces: +- **PDF file** at the specified outputPath +- **16:9 aspect ratio** (1280x720px per slide) +- **Print-ready** quality +- **Embedded fonts** for portability +`; + +export default skill; diff --git a/apps/x/packages/core/src/application/assistant/skills/create-presentations/types.ts b/apps/x/packages/core/src/application/assistant/skills/create-presentations/types.ts new file mode 100644 index 00000000..888eb2e7 --- /dev/null +++ b/apps/x/packages/core/src/application/assistant/skills/create-presentations/types.ts @@ -0,0 +1,100 @@ +export interface SlideBase { + type: string; + title?: string; + subtitle?: string; + content?: string; +} + +export interface TitleSlide extends SlideBase { + type: 'title'; + title: string; + subtitle?: string; + presenter?: string; +} + +export interface ContentSlide extends SlideBase { + type: 'content'; + title: string; + content?: string; + items?: string[]; +} + +export interface SectionSlide extends SlideBase { + type: 'section'; + title: string; + subtitle?: string; +} + +export interface StatsSlide extends SlideBase { + type: 'stats'; + title: string; + stats: Array<{ value: string; label: string }>; + note?: string; +} + +export interface TwoColumnSlide extends SlideBase { + type: 'two-column'; + title: string; + columns: [ + { title?: string; content?: string; items?: string[] }, + { title?: string; content?: string; items?: string[] } + ]; +} + +export interface QuoteSlide extends SlideBase { + type: 'quote'; + quote: string; + attribution?: string; +} + +export interface ImageSlide extends SlideBase { + type: 'image'; + title: string; + imagePath: string; + caption?: string; +} + +export interface TeamSlide extends SlideBase { + type: 'team'; + title: string; + members: Array<{ + name: string; + role: string; + bio?: string; + photoPath?: string; + }>; +} + +export interface CTASlide extends SlideBase { + type: 'cta'; + title: string; + subtitle?: string; + contact?: string; +} + +export type Slide = + | TitleSlide + | ContentSlide + | SectionSlide + | StatsSlide + | TwoColumnSlide + | QuoteSlide + | ImageSlide + | TeamSlide + | CTASlide; + +export interface Theme { + primaryColor: string; + secondaryColor: string; + accentColor: string; + textColor: string; + textLight: string; + background: string; + backgroundAlt: string; + fontFamily: string; +} + +export interface PresentationData { + slides: Slide[]; + theme?: Partial; +} diff --git a/apps/x/packages/core/src/application/assistant/skills/index.ts b/apps/x/packages/core/src/application/assistant/skills/index.ts index ab2ca83f..391f9523 100644 --- a/apps/x/packages/core/src/application/assistant/skills/index.ts +++ b/apps/x/packages/core/src/application/assistant/skills/index.ts @@ -8,6 +8,7 @@ import mcpIntegrationSkill from "./mcp-integration/skill.js"; import meetingPrepSkill from "./meeting-prep/skill.js"; import organizeFilesSkill from "./organize-files/skill.js"; import workflowAuthoringSkill from "./workflow-authoring/skill.js"; +import createPresentationsSkill from "./create-presentations/skill.js"; import workflowRunOpsSkill from "./workflow-run-ops/skill.js"; const CURRENT_FILE = fileURLToPath(import.meta.url); @@ -29,6 +30,13 @@ type ResolvedSkill = { }; const definitions: SkillDefinition[] = [ + { + id: "create-presentations", + title: "Create Presentations", + folder: "create-presentations", + summary: "Create PDF presentations and slide decks from natural language requests using knowledge base context.", + content: createPresentationsSkill, + }, { id: "doc-collab", title: "Document Collaboration", diff --git a/apps/x/packages/core/src/application/lib/builtin-tools.ts b/apps/x/packages/core/src/application/lib/builtin-tools.ts index c6ac1475..0d3756f8 100644 --- a/apps/x/packages/core/src/application/lib/builtin-tools.ts +++ b/apps/x/packages/core/src/application/lib/builtin-tools.ts @@ -12,6 +12,7 @@ import * as workspace from "../../workspace/workspace.js"; import { IAgentsRepo } from "../../agents/repo.js"; import { WorkDir } from "../../config/config.js"; import type { ToolContext } from "./exec-tool.js"; +import { generatePresentation } from "../assistant/skills/create-presentations/presentation-generator.js"; // eslint-disable-next-line @typescript-eslint/no-unused-vars const BuiltinToolsSchema = z.record(z.string(), z.object({ @@ -606,6 +607,71 @@ export const BuiltinTools: z.infer = { }, }, + generatePresentation: { + description: 'Generate a PDF presentation from slide data. Creates a 16:9 PDF with styled slides.', + inputSchema: z.object({ + slides: z.array(z.object({ + type: z.enum(['title', 'content', 'section', 'stats', 'two-column', 'quote', 'image', 'team', 'cta']), + title: z.string().optional(), + subtitle: z.string().optional(), + content: z.string().optional(), + presenter: z.string().optional(), + items: z.array(z.string()).optional(), + stats: z.array(z.object({ value: z.string(), label: z.string() })).optional(), + note: z.string().optional(), + columns: z.array(z.object({ + title: z.string().optional(), + content: z.string().optional(), + items: z.array(z.string()).optional(), + })).optional(), + quote: z.string().optional(), + attribution: z.string().optional(), + imagePath: z.string().optional(), + caption: z.string().optional(), + members: z.array(z.object({ + name: z.string(), + role: z.string(), + bio: z.string().optional(), + photoPath: z.string().optional(), + })).optional(), + contact: z.string().optional(), + })).describe('Array of slide objects'), + theme: z.object({ + primaryColor: z.string().optional(), + secondaryColor: z.string().optional(), + accentColor: z.string().optional(), + textColor: z.string().optional(), + textLight: z.string().optional(), + background: z.string().optional(), + backgroundAlt: z.string().optional(), + fontFamily: z.string().optional(), + }).optional().describe('Optional theme customization'), + outputPath: z.string().describe('Absolute path for the output PDF file'), + }), + execute: async ({ slides, theme, outputPath }: { + slides: Array>; + theme?: Record; + outputPath: string; + }) => { + try { + const result = await generatePresentation( + { slides: slides as never, theme }, + outputPath, + ); + return { + success: true, + outputPath: result, + slideCount: slides.length, + }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Unknown error', + }; + } + }, + }, + executeCommand: { description: 'Execute a shell command and return the output. Use this to run bash/shell commands.', inputSchema: z.object({ diff --git a/apps/x/packages/core/tsconfig.json b/apps/x/packages/core/tsconfig.json index 3e5b01a3..d9f2b13c 100644 --- a/apps/x/packages/core/tsconfig.json +++ b/apps/x/packages/core/tsconfig.json @@ -4,7 +4,8 @@ "declaration": true, "outDir": "dist", "rootDir": "src", - "types": ["node"] + "types": ["node"], + "jsx": "react-jsx" }, "include": [ "src" diff --git a/apps/x/pnpm-lock.yaml b/apps/x/pnpm-lock.yaml index 76d41173..5ea5f4d3 100644 --- a/apps/x/pnpm-lock.yaml +++ b/apps/x/pnpm-lock.yaml @@ -299,6 +299,12 @@ importers: '@openrouter/ai-sdk-provider': specifier: ^1.2.6 version: 1.5.4(ai@5.0.117(zod@4.2.1))(zod@4.2.1) + '@react-pdf/renderer': + specifier: ^4.3.2 + version: 4.3.2(react@19.2.3) + '@types/react': + specifier: ^19.2.7 + version: 19.2.7 '@x/shared': specifier: workspace:* version: link:../shared @@ -329,6 +335,9 @@ importers: openid-client: specifier: ^6.8.1 version: 6.8.1 + react: + specifier: ^19.2.3 + version: 19.2.3 yaml: specifier: ^2.8.2 version: 2.8.2 @@ -631,6 +640,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -1947,6 +1960,49 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@react-pdf/fns@3.1.2': + resolution: {integrity: sha512-qTKGUf0iAMGg2+OsUcp9ffKnKi41RukM/zYIWMDJ4hRVYSr89Q7e3wSDW/Koqx3ea3Uy/z3h2y3wPX6Bdfxk6g==} + + '@react-pdf/font@4.0.4': + resolution: {integrity: sha512-8YtgGtL511txIEc9AjiilpZ7yjid8uCd8OGUl6jaL3LIHnrToUupSN4IzsMQpVTCMYiDLFnDNQzpZsOYtRS/Pg==} + + '@react-pdf/image@3.0.4': + resolution: {integrity: sha512-z0ogVQE0bKqgXQ5smgzIU857rLV7bMgVdrYsu3UfXDDLSzI7QPvzf6MFTFllX6Dx2rcsF13E01dqKPtJEM799g==} + + '@react-pdf/layout@4.4.2': + resolution: {integrity: sha512-gNu2oh8MiGR+NJZYTJ4c4q0nWCESBI6rKFiodVhE7OeVAjtzZzd6l65wsN7HXdWJqOZD3ttD97iE+tf5SOd/Yg==} + + '@react-pdf/pdfkit@4.1.0': + resolution: {integrity: sha512-Wm/IOAv0h/U5Ra94c/PltFJGcpTUd/fwVMVeFD6X9tTTPCttIwg0teRG1Lqq617J8K4W7jpL/B0HTH0mjp3QpQ==} + + '@react-pdf/png-js@3.0.0': + resolution: {integrity: sha512-eSJnEItZ37WPt6Qv5pncQDxLJRK15eaRwPT+gZoujP548CodenOVp49GST8XJvKMFt9YqIBzGBV/j9AgrOQzVA==} + + '@react-pdf/primitives@4.1.1': + resolution: {integrity: sha512-IuhxYls1luJb7NUWy6q5avb1XrNaVj9bTNI40U9qGRuS6n7Hje/8H8Qi99Z9UKFV74bBP3DOf3L1wV2qZVgVrQ==} + + '@react-pdf/reconciler@2.0.0': + resolution: {integrity: sha512-7zaPRujpbHSmCpIrZ+b9HSTJHthcVZzX0Wx7RzvQGsGBUbHP4p6s5itXrAIOuQuPvDepoHGNOvf6xUuMVvdoyw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@react-pdf/render@4.3.2': + resolution: {integrity: sha512-el5KYM1sH/PKcO4tRCIm8/AIEmhtraaONbwCrBhFdehoGv6JtgnXiMxHGAvZbI5kEg051GbyP+XIU6f6YbOu6Q==} + + '@react-pdf/renderer@4.3.2': + resolution: {integrity: sha512-EhPkj35gO9rXIyyx29W3j3axemvVY5RigMmlK4/6Ku0pXB8z9PEE/sz4ZBOShu2uot6V4xiCR3aG+t9IjJJlBQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@react-pdf/stylesheet@6.1.2': + resolution: {integrity: sha512-E3ftGRYUQGKiN3JOgtGsLDo0hGekA6dmkmi/MYACytmPTKxQRBSO3126MebmCq+t1rgU9uRlREIEawJ+8nzSbw==} + + '@react-pdf/textkit@6.1.0': + resolution: {integrity: sha512-sFlzDC9CDFrJsnL3B/+NHrk9+Advqk7iJZIStiYQDdskbow8GF/AGYrpIk+vWSnh35YxaGbHkqXq53XOxnyrjQ==} + + '@react-pdf/types@2.9.2': + resolution: {integrity: sha512-dufvpKId9OajLLbgn9q7VLUmyo1Jf+iyGk2ZHmCL8nIDtL8N1Ejh9TH7+pXXrR0tdie1nmnEb5Bz9U7g4hI4/g==} + '@remirror/core-constants@3.0.0': resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} @@ -2307,6 +2363,9 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + '@szmarczak/http-timer@4.0.6': resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -2931,6 +2990,9 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + abs-svg-path@0.1.1: + resolution: {integrity: sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==} + accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -3071,6 +3133,10 @@ packages: base32-encode@1.2.0: resolution: {integrity: sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A==} + base64-js@0.0.8: + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} + engines: {node: '>= 0.4'} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -3078,6 +3144,9 @@ packages: resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} hasBin: true + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} @@ -3114,6 +3183,12 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + brotli@1.3.3: + resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} + + browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -3251,6 +3326,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -3271,6 +3350,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -3369,6 +3451,9 @@ packages: resolution: {integrity: sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==} engines: {node: '>=12.10'} + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -3612,6 +3697,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dfa@1.2.0: + resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==} + dir-compare@4.2.0: resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} @@ -3674,6 +3762,9 @@ packages: engines: {node: '>= 12.20.55'} hasBin: true + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -3975,6 +4066,9 @@ packages: debug: optional: true + fontkit@2.0.4: + resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -4298,6 +4392,12 @@ packages: hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + hsl-to-hex@1.0.0: + resolution: {integrity: sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==} + + hsl-to-rgb-for-reals@1.1.1: + resolution: {integrity: sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==} + html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} @@ -4330,6 +4430,9 @@ packages: humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + hyphen@1.14.1: + resolution: {integrity: sha512-kvL8xYl5QMTh+LwohVN72ciOxC0OEV79IPdJSTwEXok9y9QHebXGdFgrED4sWfiax/ODx++CAMk3hMy4XPJPOw==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -4419,6 +4522,9 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -4506,6 +4612,9 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jay-peg@1.1.1: + resolution: {integrity: sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==} + jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} @@ -4679,6 +4788,9 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + linebreak@1.1.0: + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} @@ -4735,6 +4847,10 @@ packages: 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 + lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -4855,6 +4971,9 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-engine@1.0.3: + resolution: {integrity: sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==} + media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -5200,6 +5319,9 @@ packages: normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + normalize-svg-path@1.1.0: + resolution: {integrity: sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==} + normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} @@ -5317,6 +5439,12 @@ packages: package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -5335,6 +5463,9 @@ packages: resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} engines: {node: '>=0.10.0'} + parse-svg-path@0.1.2: + resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -5428,6 +5559,9 @@ packages: points-on-path@0.2.1: resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -5472,6 +5606,9 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} @@ -5565,6 +5702,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + quick-lru@5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} @@ -5588,6 +5728,9 @@ packages: peerDependencies: react: ^19.2.3 + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-refresh@0.18.0: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} @@ -5745,6 +5888,9 @@ packages: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + restructure@3.0.2: + resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -5807,6 +5953,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.25.0-rc-603e6108-20241029: + resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -5897,6 +6046,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -6034,6 +6186,9 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svg-arc-to-cubic-bezier@3.2.0: + resolution: {integrity: sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==} + tailwind-merge@3.4.0: resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} @@ -6077,6 +6232,9 @@ packages: tiny-each-async@2.0.3: resolution: {integrity: sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==} + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -6201,6 +6359,12 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + unicode-properties@1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + + unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -6325,6 +6489,10 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite-compatible-readable-stream@3.6.1: + resolution: {integrity: sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==} + engines: {node: '>= 6'} + vite@7.3.0: resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -6508,6 +6676,9 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} + yoga-layout@3.2.1: + resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + zod-to-json-schema@3.25.1: resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: @@ -7159,6 +7330,8 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/runtime@7.28.6': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -8648,6 +8821,107 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@react-pdf/fns@3.1.2': {} + + '@react-pdf/font@4.0.4': + dependencies: + '@react-pdf/pdfkit': 4.1.0 + '@react-pdf/types': 2.9.2 + fontkit: 2.0.4 + is-url: 1.2.4 + + '@react-pdf/image@3.0.4': + dependencies: + '@react-pdf/png-js': 3.0.0 + jay-peg: 1.1.1 + + '@react-pdf/layout@4.4.2': + dependencies: + '@react-pdf/fns': 3.1.2 + '@react-pdf/image': 3.0.4 + '@react-pdf/primitives': 4.1.1 + '@react-pdf/stylesheet': 6.1.2 + '@react-pdf/textkit': 6.1.0 + '@react-pdf/types': 2.9.2 + emoji-regex-xs: 1.0.0 + queue: 6.0.2 + yoga-layout: 3.2.1 + + '@react-pdf/pdfkit@4.1.0': + dependencies: + '@babel/runtime': 7.28.6 + '@react-pdf/png-js': 3.0.0 + browserify-zlib: 0.2.0 + crypto-js: 4.2.0 + fontkit: 2.0.4 + jay-peg: 1.1.1 + linebreak: 1.1.0 + vite-compatible-readable-stream: 3.6.1 + + '@react-pdf/png-js@3.0.0': + dependencies: + browserify-zlib: 0.2.0 + + '@react-pdf/primitives@4.1.1': {} + + '@react-pdf/reconciler@2.0.0(react@19.2.3)': + dependencies: + object-assign: 4.1.1 + react: 19.2.3 + scheduler: 0.25.0-rc-603e6108-20241029 + + '@react-pdf/render@4.3.2': + dependencies: + '@babel/runtime': 7.28.6 + '@react-pdf/fns': 3.1.2 + '@react-pdf/primitives': 4.1.1 + '@react-pdf/textkit': 6.1.0 + '@react-pdf/types': 2.9.2 + abs-svg-path: 0.1.1 + color-string: 1.9.1 + normalize-svg-path: 1.1.0 + parse-svg-path: 0.1.2 + svg-arc-to-cubic-bezier: 3.2.0 + + '@react-pdf/renderer@4.3.2(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.6 + '@react-pdf/fns': 3.1.2 + '@react-pdf/font': 4.0.4 + '@react-pdf/layout': 4.4.2 + '@react-pdf/pdfkit': 4.1.0 + '@react-pdf/primitives': 4.1.1 + '@react-pdf/reconciler': 2.0.0(react@19.2.3) + '@react-pdf/render': 4.3.2 + '@react-pdf/types': 2.9.2 + events: 3.3.0 + object-assign: 4.1.1 + prop-types: 15.8.1 + queue: 6.0.2 + react: 19.2.3 + + '@react-pdf/stylesheet@6.1.2': + dependencies: + '@react-pdf/fns': 3.1.2 + '@react-pdf/types': 2.9.2 + color-string: 1.9.1 + hsl-to-hex: 1.0.0 + media-engine: 1.0.3 + postcss-value-parser: 4.2.0 + + '@react-pdf/textkit@6.1.0': + dependencies: + '@react-pdf/fns': 3.1.2 + bidi-js: 1.0.3 + hyphen: 1.14.1 + unicode-properties: 1.4.1 + + '@react-pdf/types@2.9.2': + dependencies: + '@react-pdf/font': 4.0.4 + '@react-pdf/primitives': 4.1.1 + '@react-pdf/stylesheet': 6.1.2 + '@remirror/core-constants@3.0.0': {} '@rolldown/pluginutils@1.0.0-beta.53': {} @@ -9093,6 +9367,10 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@swc/helpers@0.5.18': + dependencies: + tslib: 2.8.1 + '@szmarczak/http-timer@4.0.6': dependencies: defer-to-connect: 2.0.1 @@ -9827,6 +10105,8 @@ snapshots: abbrev@1.1.1: {} + abs-svg-path@0.1.1: {} + accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -9966,10 +10246,16 @@ snapshots: to-data-view: 1.1.0 optional: true + base64-js@0.0.8: {} + base64-js@1.5.1: {} baseline-browser-mapping@2.9.11: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + bignumber.js@9.3.1: {} bl@4.1.0: @@ -10019,6 +10305,14 @@ snapshots: dependencies: fill-range: 7.1.1 + brotli@1.3.3: + dependencies: + base64-js: 1.5.1 + + browserify-zlib@0.2.0: + dependencies: + pako: 1.0.11 + browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.11 @@ -10180,6 +10474,8 @@ snapshots: clone@1.0.4: {} + clone@2.1.2: {} + clsx@2.1.1: {} cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): @@ -10203,6 +10499,11 @@ snapshots: color-name@1.1.4: {} + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + colorette@2.0.20: {} combined-stream@1.0.8: @@ -10283,6 +10584,8 @@ snapshots: cross-zip@4.0.1: {} + crypto-js@4.2.0: {} + css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -10542,6 +10845,8 @@ snapshots: dependencies: dequal: 2.0.3 + dfa@1.2.0: {} + dir-compare@4.2.0: dependencies: minimatch: 3.1.2 @@ -10655,6 +10960,8 @@ snapshots: transitivePeerDependencies: - supports-color + emoji-regex-xs@1.0.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -11046,6 +11353,18 @@ snapshots: follow-redirects@1.15.11: {} + fontkit@2.0.4: + dependencies: + '@swc/helpers': 0.5.18 + brotli: 1.3.3 + clone: 2.1.2 + dfa: 1.2.0 + fast-deep-equal: 3.1.3 + restructure: 3.0.2 + tiny-inflate: 1.0.3 + unicode-properties: 1.4.1 + unicode-trie: 2.0.0 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -11535,6 +11854,12 @@ snapshots: hosted-git-info@2.8.9: {} + hsl-to-hex@1.0.0: + dependencies: + hsl-to-rgb-for-reals: 1.1.1 + + hsl-to-rgb-for-reals@1.1.1: {} + html-url-attributes@3.0.1: {} html-void-elements@3.0.0: {} @@ -11580,6 +11905,8 @@ snapshots: dependencies: ms: 2.1.3 + hyphen@1.14.1: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -11645,6 +11972,8 @@ snapshots: is-arrayish@0.2.1: {} + is-arrayish@0.3.4: {} + is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -11712,6 +12041,10 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jay-peg@1.1.1: + dependencies: + restructure: 3.0.2 + jest-worker@27.5.1: dependencies: '@types/node': 25.0.3 @@ -11865,6 +12198,11 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + linebreak@1.1.0: + dependencies: + base64-js: 0.0.8 + unicode-trie: 2.0.0 + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 @@ -11925,6 +12263,10 @@ snapshots: longest-streak@3.1.0: {} + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + lower-case@2.0.2: dependencies: tslib: 2.8.1 @@ -12173,6 +12515,8 @@ snapshots: mdurl@2.0.0: {} + media-engine@1.0.3: {} + media-typer@1.1.0: {} mem@4.3.0: @@ -12628,6 +12972,10 @@ snapshots: semver: 5.7.2 validate-npm-package-license: 3.0.4 + normalize-svg-path@1.1.0: + dependencies: + svg-arc-to-cubic-bezier: 3.2.0 + normalize-url@6.1.0: {} npm-run-path@2.0.2: @@ -12742,6 +13090,10 @@ snapshots: package-manager-detector@1.6.0: {} + pako@0.2.9: {} + + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -12769,6 +13121,8 @@ snapshots: dependencies: error-ex: 1.3.4 + parse-svg-path@0.1.2: {} + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -12845,6 +13199,8 @@ snapshots: path-data-parser: 0.1.0 points-on-curve: 0.2.0 + postcss-value-parser@4.2.0: {} + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -12888,6 +13244,12 @@ snapshots: err-code: 2.0.3 retry: 0.12.0 + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + property-information@7.1.0: {} prosemirror-changeset@2.3.1: @@ -13032,6 +13394,10 @@ snapshots: queue-microtask@1.2.3: {} + queue@6.0.2: + dependencies: + inherits: 2.0.4 + quick-lru@5.1.1: {} random-path@0.1.2: @@ -13058,6 +13424,8 @@ snapshots: react: 19.2.3 scheduler: 0.27.0 + react-is@16.13.1: {} + react-refresh@0.18.0: {} react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.2.3): @@ -13248,6 +13616,8 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + restructure@3.0.2: {} + retry@0.12.0: {} reusify@1.1.0: {} @@ -13340,6 +13710,8 @@ snapshots: safer-buffer@2.1.2: {} + scheduler@0.25.0-rc-603e6108-20241029: {} + scheduler@0.27.0: {} schema-utils@4.3.3: @@ -13453,6 +13825,10 @@ snapshots: signal-exit@4.1.0: {} + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + slice-ansi@5.0.0: dependencies: ansi-styles: 6.2.3 @@ -13618,6 +13994,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svg-arc-to-cubic-bezier@3.2.0: {} + tailwind-merge@3.4.0: {} tailwindcss@4.1.18: {} @@ -13660,6 +14038,8 @@ snapshots: tiny-each-async@2.0.3: optional: true + tiny-inflate@1.0.3: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -13770,6 +14150,16 @@ snapshots: undici-types@7.16.0: {} + unicode-properties@1.4.1: + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + + unicode-trie@2.0.0: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + unified@11.0.5: dependencies: '@types/unist': 3.0.3 @@ -13903,6 +14293,12 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 + vite-compatible-readable-stream@3.6.1: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(yaml@2.8.2): dependencies: esbuild: 0.27.2 @@ -14082,6 +14478,8 @@ snapshots: yoctocolors-cjs@2.1.3: {} + yoga-layout@3.2.1: {} + zod-to-json-schema@3.25.1(zod@4.2.1): dependencies: zod: 4.2.1