diff --git a/backend/src/build-system/__tests__/test-file-create.spec.ts b/backend/src/build-system/__tests__/test-file-create.spec.ts index 3058a30e..521cdb5d 100644 --- a/backend/src/build-system/__tests__/test-file-create.spec.ts +++ b/backend/src/build-system/__tests__/test-file-create.spec.ts @@ -1,7 +1,7 @@ import * as fs from 'fs-extra'; import * as path from 'path'; -import { FileGeneratorHandler } from '../handlers/file-generate'; // Update with actual file path to the handler -import * as normalizePath from 'normalize-path'; +import normalizePath from 'normalize-path'; +import { FileGeneratorHandler } from '../handlers/file-manager/file-generate'; describe('FileGeneratorHandler', () => { const projectSrcPath = normalizePath( diff --git a/backend/src/build-system/__tests__/test-generate-doc.spec.ts b/backend/src/build-system/__tests__/test-generate-doc.spec.ts index 3cdad1ff..2e818301 100644 --- a/backend/src/build-system/__tests__/test-generate-doc.spec.ts +++ b/backend/src/build-system/__tests__/test-generate-doc.spec.ts @@ -4,22 +4,14 @@ import { BuildSequence } from '../types'; import { BuildSequenceExecutor } from '../executor'; import * as fs from 'fs'; import * as path from 'path'; +import { writeToFile } from './utils'; describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { // Generate a unique folder with a timestamp const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); - const logFolderPath = `./log-${timestamp}`; + const logFolderPath = `./logs/generate-docs-${timestamp}`; fs.mkdirSync(logFolderPath, { recursive: true }); - // Utility function to extract Markdown content and write to .md files - const writeMarkdownToFile = (handlerName: string, data: any) => { - // Extract "data" field and remove surrounding Markdown code block formatting - const markdownContent = data?.data?.replace(/```/g, '') || ''; - const filePath = path.join(logFolderPath, `${handlerName}.md`); - fs.writeFileSync(filePath, markdownContent, 'utf8'); - console.log(`Logged ${handlerName} result data to ${filePath}`); - }; - it('should execute the full sequence and log results to individual files', async () => { const sequence: BuildSequence = { id: 'test-sequence', @@ -32,7 +24,7 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { name: 'Generate PRD', nodes: [ { - id: 'op:PRD::STATE:GENERATE', + id: 'op:PRD', name: 'PRD Generation Node', type: 'ANALYSIS', subType: 'PRD', @@ -44,11 +36,11 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { name: 'Generate UX Sitemap Document', nodes: [ { - id: 'op:UXSMD::STATE:GENERATE', + id: 'op:UX:SMD', name: 'UX Sitemap Document Node', type: 'UX', subType: 'SITEMAP', - requires: ['op:PRD::STATE:GENERATE'], + requires: ['op:PRD'], }, ], }, @@ -57,11 +49,11 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { name: 'Generate UX Sitemap Structure', nodes: [ { - id: 'op:UXSMS::STATE:GENERATE', + id: 'op:UX:SMS', name: 'UX Sitemap Structure Node', type: 'UX', subType: 'VIEWS', - requires: ['op:UXSMD::STATE:GENERATE'], + requires: ['op:UX:SMD'], }, ], }, @@ -70,9 +62,9 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { name: 'UX Data Map Document', nodes: [ { - id: 'op:UX_DATAMAP::STATE:GENERATE', + id: 'op:UX:DATAMAP:DOC', name: 'UX Data Map Document node', - requires: ['op:UXSMD::STATE:GENERATE'], + requires: ['op:UX:SMD'], }, ], }, @@ -81,12 +73,12 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { name: 'file structure generation', nodes: [ { - id: 'op:FSTRUCT::STATE:GENERATE', + id: 'op:FILE:STRUCT', name: 'file structure generation', - requires: [ - 'op:UXSMD::STATE:GENERATE', - 'op:UX_DATAMAP::STATE:GENERATE', - ], + requires: ['op:UX:SMD', 'op:UX:DATAMAP:DOC'], + options: { + projectPart: 'frontend', + }, }, ], }, @@ -95,11 +87,12 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { name: 'File_Arch Document', nodes: [ { - id: 'op:FILE_ARCH::STATE:GENERATE', + id: 'op:FILE:ARCH', name: 'File_Arch', requires: [ - 'op:FSTRUCT::STATE:GENERATE', - 'op:UX_DATAMAP::STATE:GENERATE', + 'op:FILE:STRUCT', + //TODO: here use datamap doc rather than datamap struct, we have to change this + 'op:UX:DATAMAP:DOC', ], }, ], @@ -110,19 +103,19 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS', () => { const context = new BuilderContext(sequence, 'test'); // Set input data for context - context.setData('projectName', 'spotify like music web'); - context.setData('description', 'user can play music'); - context.setData('platform', 'web'); + context.setGlobalContext('projectName', 'spotify like music web'); + context.setGlobalContext('description', 'user can play music'); + context.setGlobalContext('platform', 'web'); try { await BuildSequenceExecutor.executeSequence(sequence, context); for (const step of sequence.steps) { for (const node of step.nodes) { - const resultData = await context.getResult(node.id); + const resultData = await context.getNodeData(node.id); console.log(resultData); if (resultData) { - writeMarkdownToFile(node.name.replace(/ /g, '_'), resultData); + writeToFile(logFolderPath, node.id, resultData); } } } diff --git a/backend/src/build-system/__tests__/test.backend-code-generator.spec.ts b/backend/src/build-system/__tests__/test.backend-code-generator.spec.ts index b70d7bca..5b80ed41 100644 --- a/backend/src/build-system/__tests__/test.backend-code-generator.spec.ts +++ b/backend/src/build-system/__tests__/test.backend-code-generator.spec.ts @@ -1,9 +1,10 @@ /* eslint-disable no-console */ import { BuilderContext } from 'src/build-system/context'; -import { BuildResult, BuildSequence } from '../types'; +import { BuildSequence } from '../types'; import { BuildSequenceExecutor } from '../executor'; import * as fs from 'fs'; import * as path from 'path'; +import { writeToFile } from './utils'; describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGenerator', () => { // Generate a unique folder with a timestamp @@ -11,44 +12,21 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener const logFolderPath = `./logs/backend_code_generator-${timestamp}`; fs.mkdirSync(logFolderPath, { recursive: true }); - /** - * Utility function to extract content within tags and write to .md files. - * @param handlerName - The name of the handler/node. - * @param data - The data returned by the handler/node. - */ - const writeMarkdownToFile = (handlerName: string, data: BuildResult) => { - try { - // Extract "data" field and ensure it's a string - const content: string = data?.data; - if (typeof content !== 'string') { - throw new Error(`Invalid data format for handler: ${handlerName}`); - } - - const sanitizedHandlerName = handlerName.replace(/[^a-zA-Z0-9_-]/g, '_'); - const filePath = path.join(logFolderPath, `${sanitizedHandlerName}.md`); - fs.writeFileSync(filePath, content, 'utf8'); - console.log(`Logged ${handlerName} result data to ${filePath}`); - } catch (error) { - console.error(`Failed to write markdown for ${handlerName}:`, error); - throw error; - } - }; - it('should execute the backend code generation sequence and log results to individual files', async () => { // Define the build sequence up to Backend Code Generator const sequence: BuildSequence = { id: 'test-backend-sequence', version: '1.0.0', - name: 'Test PRD to Backend Code Generation Sequence', - description: - 'Testing sequence execution from PRD to Backend Code Generation', + name: 'Spotify-like Music Web', + description: 'Users can play music', + databaseType: 'SQLite', steps: [ { id: 'step-1', name: 'Generate PRD', nodes: [ { - id: 'op:PRD::STATE:GENERATE', + id: 'op:PRD', name: 'PRD Generation Node', type: 'ANALYSIS', subType: 'PRD', @@ -60,11 +38,11 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener name: 'Generate UX Sitemap Document', nodes: [ { - id: 'op:UXSMD::STATE:GENERATE', + id: 'op:UX:SMD', name: 'UX Sitemap Document Node', type: 'UX', subType: 'SITEMAP', - requires: ['op:PRD::STATE:GENERATE'], + requires: ['op:PRD'], }, ], }, @@ -73,11 +51,11 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener name: 'Generate UX Data Map Document', nodes: [ { - id: 'op:UX_DATAMAP::STATE:GENERATE', + id: 'op:UX:DATAMAP:DOC', name: 'UX Data Map Document Node', type: 'UX', subType: 'DATAMAP', - requires: ['op:UXSMD::STATE:GENERATE'], + requires: ['op:UX:SMD'], }, ], }, @@ -86,11 +64,11 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener name: 'Generate Database Requirements', nodes: [ { - id: 'op:DATABASE_REQ::STATE:GENERATE', + id: 'op:DATABASE_REQ', name: 'Database Requirements Node', type: 'DATABASE', subType: 'SCHEMAS', - requires: ['op:UX_DATAMAP::STATE:GENERATE'], + requires: ['op:UX:DATAMAP:DOC'], }, ], }, @@ -103,7 +81,7 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener name: 'Database Schemas Node', type: 'DATABASE', subType: 'SCHEMAS', - requires: ['op:DATABASE_REQ::STATE:GENERATE'], + requires: ['op:DATABASE_REQ'], }, ], }, @@ -112,13 +90,10 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener name: 'Generate Backend Code', nodes: [ { - id: 'op:BACKEND_CODE::STATE:GENERATE', + id: 'op:BACKEND:CODE', name: 'Backend Code Generator Node', type: 'BACKEND', - requires: [ - 'op:DATABASE:SCHEMAS', - 'op:UX_DATAMAP::STATE:GENERATE', - ], + requires: ['op:DATABASE:SCHEMAS', 'op:UX:DATAMAP:DOC'], }, ], }, @@ -128,12 +103,6 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener // Initialize the BuilderContext with the defined sequence and environment const context = new BuilderContext(sequence, 'test-env'); - // Set input data for context - context.setData('projectName', 'Spotify-like Music Web'); - context.setData('description', 'Users can play music'); - context.setData('platform', 'web'); - context.setData('databaseType', 'SQLite'); // Can be 'PostgreSQL', 'MongoDB', etc., based on your needs - try { // Execute the build sequence await BuildSequenceExecutor.executeSequence(sequence, context); @@ -141,17 +110,16 @@ describe('Sequence: PRD -> UXSD -> UXDD -> UXSS -> DBSchemas -> BackendCodeGener // Iterate through each step and node to retrieve and log results for (const step of sequence.steps) { for (const node of step.nodes) { - const resultData = await context.getResult(node.id); + const resultData = await context.getNodeData(node.id); console.log(`Result for ${node.name}:`, resultData); - if (resultData && resultData.success) { - writeMarkdownToFile(node.name, resultData); - } else if (resultData && !resultData.success) { + if (resultData) { + writeToFile(logFolderPath, node.name, resultData); + } else { console.error( `Handler ${node.name} failed with error:`, resultData.error, ); - // Optionally, you can log this to a separate file or handle it as needed } } } diff --git a/backend/src/build-system/__tests__/test.file-arch.spec.ts b/backend/src/build-system/__tests__/test.file-arch.spec.ts index 7627185d..1d8ffa6b 100644 --- a/backend/src/build-system/__tests__/test.file-arch.spec.ts +++ b/backend/src/build-system/__tests__/test.file-arch.spec.ts @@ -1,7 +1,7 @@ import { BuilderContext } from 'src/build-system/context'; -import { FileArchGenerateHandler } from '../handlers/file-arch'; import markdownToTxt from 'markdown-to-txt'; import { readFileSync } from 'fs-extra'; +import { FileArchGenerateHandler } from '../handlers/file-manager/file-arch'; describe('FileArchGenerateHandler', () => { it('should generate file architecture document', async () => { @@ -23,8 +23,9 @@ describe('FileArchGenerateHandler', () => { const dataMapStruct = markdownToTxt( readFileSync('./datamap-structure.md', 'utf-8'), ); - - const result = await handler.run(context, fileStructure, dataMapStruct); + context.setNodeData('op:FILE:STRUCT', fileStructure); + context.setNodeData('op:UX:DATAMAP:DOC', dataMapStruct); + const result = await handler.run(context); console.log(result); }, 30000); }); diff --git a/backend/src/build-system/__tests__/testVirtualDir.spec.ts b/backend/src/build-system/__tests__/testVirtualDir.spec.ts index cfcc2ca6..e919d8d0 100644 --- a/backend/src/build-system/__tests__/testVirtualDir.spec.ts +++ b/backend/src/build-system/__tests__/testVirtualDir.spec.ts @@ -1,7 +1,7 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import { VirtualDirectory } from '../virtual-dir'; -import * as normalizePath from 'normalize-path'; +import normalizePath from 'normalize-path'; describe('VirtualDirectory', () => { const structMdFilePath = normalizePath( diff --git a/backend/src/build-system/__tests__/utils.ts b/backend/src/build-system/__tests__/utils.ts new file mode 100644 index 00000000..ff134a9a --- /dev/null +++ b/backend/src/build-system/__tests__/utils.ts @@ -0,0 +1,48 @@ +import * as fs from 'fs'; +import * as path from 'path'; +/** + * Utility function to write content to a file in a clean, formatted manner. + * @param handlerName - The name of the handler. + * @param data - The data to be written to the file. + */ +export const writeToFile = ( + rootPath: string, + handlerName: string, + data: string | object, +): void => { + try { + // Sanitize handler name to prevent illegal file names + const sanitizedHandlerName = handlerName.replace(/[^a-zA-Z0-9_-]/g, '_'); + const filePath = path.join(rootPath, `${sanitizedHandlerName}.md`); + + // Generate clean and readable content + const formattedContent = formatContent(data); + + // Write the formatted content to the file + fs.writeFileSync(filePath, formattedContent, 'utf8'); + console.log(`Successfully wrote data for ${handlerName} to ${filePath}`); + } catch (error) { + console.error(`Failed to write data for ${handlerName}:`, error); + throw error; + } +}; + +/** + * Formats the content for writing to the file. + * @param data - The content to format (either a string or an object). + * @returns A formatted string. + */ +export const formatContent = (data: string | object): string => { + if (typeof data === 'string') { + // Remove unnecessary escape characters and normalize newlines + return data + .replace(/\\n/g, '\n') // Handle escaped newlines + .replace(/\\t/g, '\t'); // Handle escaped tabs + } else if (typeof data === 'object') { + // Pretty-print JSON objects with 2-space indentation + return JSON.stringify(data, null, 2); + } else { + // Convert other types to strings + return String(data); + } +}; diff --git a/backend/src/build-system/context.ts b/backend/src/build-system/context.ts index c1b8883b..5d1ab5b4 100644 --- a/backend/src/build-system/context.ts +++ b/backend/src/build-system/context.ts @@ -4,33 +4,48 @@ import { BuildNode, BuildResult, BuildSequence, + NodeOutputMap, } from './types'; import { Logger } from '@nestjs/common'; import { VirtualDirectory } from './virtual-dir'; import { ModelProvider } from 'src/common/model-provider'; +/** + * Predefined global keys for context. + */ import { v4 as uuidv4 } from 'uuid'; export type GlobalDataKeys = | 'projectName' | 'description' | 'platform' + | 'databaseType' | 'projectUUID'; -type ContextData = { - [key in GlobalDataKeys]: string; -} & Record; +/** + * ContextData type, allowing dynamic keys and predefined keys. + */ +type ContextData = Record; + +/** + * BuilderContext manages: + * - Execution state of nodes (completed, pending, failed, waiting) + * - Global and arbitrary data (projectName, description, etc.) + * - Node output data, stored after successful execution + * - References to model provider, handler manager, virtual directory + */ export class BuilderContext { - private state: BuildExecutionState = { + private executionState: BuildExecutionState = { completed: new Set(), pending: new Set(), failed: new Set(), waiting: new Set(), }; - private logger; - private data: Record = {}; - // Store the results of the nodes - private results: Map = new Map(); + + private logger: Logger; + private globalContext: Map = new Map(); // Stores global context data + private nodeData: Map = new Map(); // Stores node outputs + private handlerManager: BuildHandlerManager; public model: ModelProvider; public virtualDirectory: VirtualDirectory; @@ -44,32 +59,42 @@ export class BuilderContext { this.logger = new Logger(`builder-context-${id}`); this.virtualDirectory = new VirtualDirectory(); + // Initialize global context with default values + this.globalContext.set('projectName', sequence.name); + this.globalContext.set('description', sequence.description || ''); + this.globalContext.set('platform', 'web'); + this.globalContext.set('databaseType', sequence.databaseType || 'SQLite'); const projectUUID = uuidv4(); - this.setData('projectUUID', projectUUID); + this.globalContext.set('projectUUID', projectUUID); } + /** + * Checks if a node can be executed. + * @param nodeId The ID of the node. + */ canExecute(nodeId: string): boolean { const node = this.findNode(nodeId); if (!node) return false; - if (this.state.completed.has(nodeId) || this.state.pending.has(nodeId)) { - console.log(`Node ${nodeId} is already completed or pending.`); + if ( + this.executionState.completed.has(nodeId) || + this.executionState.pending.has(nodeId) + ) { + this.logger.debug(`Node ${nodeId} is already completed or pending.`); return false; } - return !node.requires?.some((dep) => !this.state.completed.has(dep)); - } - - private findNode(nodeId: string): BuildNode | null { - for (const step of this.sequence.steps) { - const node = step.nodes.find((n) => n.id === nodeId); - if (node) return node; - } - return null; + return !node.requires?.some( + (dep) => !this.executionState.completed.has(dep), + ); } - async run(nodeId: string, args: unknown | undefined): Promise { + /** + * Executes a node by its ID. Upon success, stores node output data. + * @param nodeId The ID of the node to execute. + */ + async executeNodeById(nodeId: string): Promise> { const node = this.findNode(nodeId); if (!node) { throw new Error(`Node not found: ${nodeId}`); @@ -80,59 +105,103 @@ export class BuilderContext { } try { - this.state.pending.add(nodeId); - const result = await this.executeNode(node, args); - this.state.completed.add(nodeId); - this.state.pending.delete(nodeId); - - // Store the result for future use - this.results.set(nodeId, result); + this.executionState.pending.add(nodeId); + const result = await this.invokeNodeHandler(node); + this.executionState.completed.add(nodeId); + this.executionState.pending.delete(nodeId); + this.nodeData.set(node.id, result.data); return result; } catch (error) { - this.state.failed.add(nodeId); - this.state.pending.delete(nodeId); + this.executionState.failed.add(nodeId); + this.executionState.pending.delete(nodeId); throw error; } } - getState(): BuildExecutionState { - return { ...this.state }; + /** + * Returns the current execution state of the build sequence. + */ + getExecutionState(): BuildExecutionState { + return { ...this.executionState }; } - setData( + /** + * Store global context data. + * @param key The key to store. + * @param value The value to store. + */ + setGlobalContext( key: Key, value: ContextData[Key], ): void { - this.data[key] = value; + this.globalContext.set(key, value); } - getData( + /** + * Retrieve global context data. + * @param key The key to retrieve. + */ + getGlobalContext( key: Key, ): ContextData[Key] | undefined { - if (!(key in this.data)) { - return undefined; - } - return this.data[key]; + return this.globalContext.get(key); } - getResult(nodeId: string): BuildResult | undefined { - return this.results.get(nodeId); + /** + * Retrieve the stored output data for a given node (typed if defined in NodeOutputMap). + * Overload 1: If nodeId is a key of NodeOutputMap, return strong-typed data. + */ + getNodeData( + nodeId: NodeId, + ): NodeOutputMap[NodeId]; + + /** + * Overload 2: If nodeId is not in NodeOutputMap, return any. + */ + getNodeData(nodeId: string): any; + + getNodeData(nodeId: string) { + return this.nodeData.get(nodeId); } + setNodeData( + nodeId: NodeId, + data: any, + ): void { + this.nodeData.set(nodeId, data); + } + + /** + * Builds the virtual directory from a given JSON content. + */ buildVirtualDirectory(jsonContent: string): boolean { return this.virtualDirectory.parseJsonStructure(jsonContent); } - private async executeNode( - node: BuildNode, - args: unknown, - ): Promise { - this.logger.log(`Executing node: ${node.id}`); + /** + * Finds a node in the sequence by its ID. + * @param nodeId Node ID to find + */ + private findNode(nodeId: string): BuildNode | null { + for (const step of this.sequence.steps) { + const node = step.nodes.find((n) => n.id === nodeId); + if (node) return node; + } + return null; + } + + /** + * Invokes the node's handler and returns its BuildResult. + * @param node The node to execute. + */ + private async invokeNodeHandler(node: BuildNode): Promise> { + this.logger.log(`Executing node handler: ${node.id}`); const handler = this.handlerManager.getHandler(node.id); if (!handler) { throw new Error(`No handler found for node: ${node.id}`); } - return handler.run(this, args); + + return handler.run(this, node.options); } } diff --git a/backend/src/build-system/executor.ts b/backend/src/build-system/executor.ts index e93a6b77..2398a893 100644 --- a/backend/src/build-system/executor.ts +++ b/backend/src/build-system/executor.ts @@ -9,35 +9,32 @@ export class BuildSequenceExecutor { ); /** - * 执行单个节点 + * Execute a single node. + * If the node is completed, do nothing. + * If dependencies aren't ready, wait and retry. */ static async executeNode( node: BuildNode, context: BuilderContext, ): Promise { try { - if (context.getState().completed.has(node.id)) { - return; // 如果节点已完成,跳过 + // Check if node is already completed + if (context.getExecutionState().completed.has(node.id)) { + return; } + // If dependencies are not met, wait and retry if (!context.canExecute(node.id)) { this.logger.log( - `Waiting for dependencies: ${node.requires?.join(', ')}`, + `Waiting for dependencies of node ${node.id}: ${node.requires?.join(', ')}`, ); await new Promise((resolve) => setTimeout(resolve, 100)); return; } - const dependenciesResults = node.requires?.map((depId) => - context.getResult(depId), - ); - - this.logger.log( - `Executing node ${node.id} with dependencies:`, - dependenciesResults, - ); - - await context.run(node.id, dependenciesResults); + this.logger.log(`Executing node ${node.id}`); + // Execute the node using the updated context method + await context.executeNodeById(node.id); } catch (error) { this.logger.error(`Error executing node ${node.id}:`, error); throw error; @@ -45,7 +42,9 @@ export class BuildSequenceExecutor { } /** - * 执行单个步骤 + * Execute a single step. + * If the step is parallel, attempt to run all nodes concurrently (respecting dependencies). + * If not parallel, run nodes in sequence. */ static async executeStep( step: BuildStep, @@ -60,19 +59,23 @@ export class BuildSequenceExecutor { const maxRetries = 10; while (remainingNodes.length > 0 && retryCount < maxRetries) { + // Identify nodes that can be executed now const executableNodes = remainingNodes.filter((node) => context.canExecute(node.id), ); if (executableNodes.length > 0) { + // Execute all currently executable nodes in parallel await Promise.all( executableNodes.map((node) => this.executeNode(node, context)), ); + // Filter out completed nodes remainingNodes = remainingNodes.filter( - (node) => !context.getState().completed.has(node.id), + (node) => !context.getExecutionState().completed.has(node.id), ); + // If progress is made, reset retryCount if (remainingNodes.length < lastLength) { retryCount = 0; lastLength = remainingNodes.length; @@ -80,11 +83,13 @@ export class BuildSequenceExecutor { retryCount++; } } else { + // No executable nodes currently, wait and retry await new Promise((resolve) => setTimeout(resolve, 100)); retryCount++; } } + // If after max retries some nodes are still not completed, throw an error if (remainingNodes.length > 0) { throw new Error( `Unable to complete all nodes in step ${step.id}. Remaining: ${remainingNodes @@ -93,23 +98,24 @@ export class BuildSequenceExecutor { ); } } else { + // Sequential execution for (const node of step.nodes) { let retryCount = 0; const maxRetries = 10; while ( - !context.getState().completed.has(node.id) && + !context.getExecutionState().completed.has(node.id) && retryCount < maxRetries ) { await this.executeNode(node, context); - if (!context.getState().completed.has(node.id)) { + if (!context.getExecutionState().completed.has(node.id)) { await new Promise((resolve) => setTimeout(resolve, 100)); retryCount++; } } - if (!context.getState().completed.has(node.id)) { + if (!context.getExecutionState().completed.has(node.id)) { this.logger.warn( `Failed to execute node ${node.id} after ${maxRetries} attempts`, ); @@ -119,7 +125,9 @@ export class BuildSequenceExecutor { } /** - * 执行整个序列 + * Execute the entire build sequence. + * Iterates through each step, executing them in order. + * If a step fails to complete all its nodes, logs a warning and returns. */ static async executeSequence( sequence: BuildSequence, @@ -131,7 +139,7 @@ export class BuildSequenceExecutor { await this.executeStep(step, context); const incompletedNodes = step.nodes.filter( - (node) => !context.getState().completed.has(node.id), + (node) => !context.getExecutionState().completed.has(node.id), ); if (incompletedNodes.length > 0) { @@ -145,6 +153,6 @@ export class BuildSequenceExecutor { } this.logger.log(`Build sequence completed: ${sequence.id}`); - this.logger.log('Final state:', context.getState()); + this.logger.log('Final execution state:', context.getExecutionState()); } } diff --git a/backend/src/build-system/handlers/backend/code-generate/index.ts b/backend/src/build-system/handlers/backend/code-generate/index.ts index f1dec055..49b2ba08 100644 --- a/backend/src/build-system/handlers/backend/code-generate/index.ts +++ b/backend/src/build-system/handlers/backend/code-generate/index.ts @@ -7,27 +7,12 @@ import { removeCodeBlockFences, } from 'src/build-system/utils/database-utils'; -/** - * Defines the expected order and types of arguments for BackendCodeHandler. - * - * @param sitemapDoc - The sitemap documentation as a string. - * @param DatamapDoc - The data analysis document as a string. - * @param currentFile - (Optional) The name of the current file. Defaults to 'backend.js'. - * @param dependencyFile - (Optional) The name of the dependency file. Defaults to 'dependencies.json'. - */ -type BackendCodeArgs = [ - sitemapDoc: string, - DatamapDoc: string, - currentFile?: string, - dependencyFile?: string, -]; - /** * BackendCodeHandler is responsible for generating the backend codebase * based on the provided sitemap and data mapping documents. */ -export class BackendCodeHandler implements BuildHandler { - readonly id = 'op:BACKEND_CODE::STATE:GENERATE'; +export class BackendCodeHandler implements BuildHandler { + readonly id = 'op:BACKEND:CODE'; readonly logger: Logger = new Logger('BackendCodeHandler'); /** @@ -36,41 +21,27 @@ export class BackendCodeHandler implements BuildHandler { * @param args - The variadic arguments required for generating the backend code. * @returns A BuildResult containing the generated code and related data. */ - async run(context: BuilderContext, ...args: any[]): Promise { + async run(context: BuilderContext): Promise> { this.logger.log('Generating Backend Codebase...'); - // Retrieve projectName from context + // Retrieve project name and database type from context const projectName = - context.getData('projectName') || 'Default Project Name'; - this.logger.debug(`Project Name: ${projectName}`); + context.getGlobalContext('projectName') || 'Default Project Name'; const databaseType = - context.getData('databaseType') || 'Default database type'; - this.logger.debug(`Database Type: ${databaseType}`); - - // Validate and extract args - if (!args || !Array.isArray(args)) { - throw new Error( - 'Backend code generation requires specific configuration arguments as an array.', - ); - } + context.getGlobalContext('databaseType') || 'Default database type'; // Destructure arguments with default values for optional parameters - const [ - sitemapDoc, - DatamapDoc, - currentFile = 'backend.js', - dependencyFile = 'dependencies.json', - ] = args as BackendCodeArgs; - - this.logger.debug( - 'Sitemap Documentation and Data Analysis Document are provided.', - ); + const sitemapDoc = context.getNodeData('op:UX:SMD'); + const datamapDoc = context.getNodeData('op:UX:DATAMAP:DOC'); + //TODO: make this backend generate similar as FileGenerateHandler, do file arch, and then generate each backend code + const currentFile = 'backend.js'; + const dependencyFile = 'dependencies.json'; // Generate the prompt using the provided documents and project name const backendCodePrompt = generateBackendCodePrompt( projectName, sitemapDoc, - DatamapDoc, + datamapDoc, databaseType, currentFile, dependencyFile, @@ -92,7 +63,6 @@ export class BackendCodeHandler implements BuildHandler { parseGenerateTag(modelResponse), ); - // Optionally, you can process or validate the generated code here this.logger.debug('Backend code generated and parsed successfully.'); return { diff --git a/backend/src/build-system/handlers/backend/requirements-document/index.ts b/backend/src/build-system/handlers/backend/requirements-document/index.ts index e0bdc6e8..5c1ee785 100644 --- a/backend/src/build-system/handlers/backend/requirements-document/index.ts +++ b/backend/src/build-system/handlers/backend/requirements-document/index.ts @@ -6,58 +6,86 @@ import { } from './prompt'; import { Logger } from '@nestjs/common'; -export class BackendRequirementHandler implements BuildHandler { - readonly id = 'op:BACKEND_REQ::STATE:GENERATE'; +type BackendRequirementResult = { + overview: string; + implementation: string; + config: { + language: string; + framework: string; + packages: Record; + }; +}; +export class BackendRequirementHandler + implements BuildHandler +{ + readonly id = 'op:BACKEND:REQ'; readonly logger: Logger = new Logger('BackendRequirementHandler'); - async run(context: BuilderContext, args: unknown): Promise { + + async run( + context: BuilderContext, + ): Promise> { this.logger.log('Generating Backend Requirements Document...'); - // Validate and extract args - if (!args || typeof args !== 'object') { - throw new Error('Backend configuration is required'); - } - // TODO: init language, framework, packages later in context - const language = context.getData('language') || 'javascript'; - const framework = context.getData('framework') || 'express'; - const packages = context.getData('packages') || {}; - // TODO: adding graphql/restful later + // Retrieve backend configuration from context + const language = context.getGlobalContext('language') || 'javascript'; + const framework = context.getGlobalContext('framework') || 'express'; + const packages = context.getGlobalContext('packages') || {}; - const { dbRequirements } = args as { - dbRequirements: string; - language: string; - framework: string; - packages: Record; - }; + const dbRequirements = context.getNodeData('op:DATABASE_REQ'); + // Generate backend overview const overviewPrompt = generateBackendOverviewPrompt( - context.getData('projectName') || 'Default Project Name', + context.getGlobalContext('projectName') || 'Default Project Name', dbRequirements, language, framework, packages, ); - const backendOverview = await context.model.chatSync( - { - content: overviewPrompt, - }, - 'gpt-4o-mini', - ); + let backendOverview: string; + try { + backendOverview = await context.model.chatSync( + { + content: overviewPrompt, + }, + 'gpt-4o-mini', + ); + } catch (error) { + this.logger.error('Error generating backend overview:', error); + return { + success: false, + error: new Error('Failed to generate backend overview.'), + }; + } + // Generate backend implementation details const implementationPrompt = generateBackendImplementationPrompt( backendOverview, language, framework, ); - const implementationDetails = await context.model.chatSync( - { - content: implementationPrompt, - }, - 'gpt-4o-mini', - ); + let implementationDetails: string; + try { + implementationDetails = await context.model.chatSync( + { + content: implementationPrompt, + }, + 'gpt-4o-mini', + ); + } catch (error) { + this.logger.error( + 'Error generating backend implementation details:', + error, + ); + return { + success: false, + error: new Error('Failed to generate backend implementation details.'), + }; + } + // Return generated data return { success: true, data: { diff --git a/backend/src/build-system/handlers/database/requirements-document/index.ts b/backend/src/build-system/handlers/database/requirements-document/index.ts index 7141b310..7cac15e2 100644 --- a/backend/src/build-system/handlers/database/requirements-document/index.ts +++ b/backend/src/build-system/handlers/database/requirements-document/index.ts @@ -4,17 +4,19 @@ import { ModelProvider } from 'src/common/model-provider'; import { prompts } from './prompt'; import { Logger } from '@nestjs/common'; -export class DatabaseRequirementHandler implements BuildHandler { - readonly id = 'op:DATABASE_REQ::STATE:GENERATE'; +export class DatabaseRequirementHandler implements BuildHandler { + readonly id = 'op:DATABASE_REQ'; readonly logger = new Logger('DatabaseRequirementHandler'); - async run(context: BuilderContext, args: unknown): Promise { + async run(context: BuilderContext): Promise> { this.logger.log('Generating Database Requirements Document...'); const projectName = - context.getData('projectName') || 'Default Project Name'; + context.getGlobalContext('projectName') || 'Default Project Name'; + + const datamapDoc = context.getNodeData('op:UX:DATAMAP:DOC'); const prompt = prompts.generateDatabaseRequirementPrompt( projectName, - args as string, + datamapDoc, ); const model = ModelProvider.getInstance(); const dbRequirementsContent = await model.chatSync( diff --git a/backend/src/build-system/handlers/database/schemas/schemas.ts b/backend/src/build-system/handlers/database/schemas/schemas.ts index e0b44244..4832e219 100644 --- a/backend/src/build-system/handlers/database/schemas/schemas.ts +++ b/backend/src/build-system/handlers/database/schemas/schemas.ts @@ -11,14 +11,6 @@ import { import { writeFile } from 'fs-extra'; import { prompts } from './prompt'; -/** - * Defines the expected order and types of arguments for DBSchemaHandler. - * - * Expected argument order: - * 0 - dbRequirements: string - */ -type DBSchemaArgs = [dbRequirements: string]; - /** * DBSchemaHandler is responsible for generating database schemas based on provided requirements. */ @@ -32,24 +24,16 @@ export class DBSchemaHandler implements BuildHandler { * @param args - The variadic arguments required for generating the database schemas. * @returns A BuildResult containing the generated schema content and related data. */ - async run(context: BuilderContext, ...args: any[]): Promise { + async run(context: BuilderContext): Promise { this.logger.log('Generating Database Schemas...'); // Retrieve projectName and databaseType from context const projectName = - context.getData('projectName') || 'Default Project Name'; - const databaseType = context.getData('databaseType') || 'PostgreSQL'; - this.logger.debug(`Project Name: ${projectName}`); - this.logger.debug(`Database Type: ${databaseType}`); - - // Validate and extract args - if (!args || !Array.isArray(args)) { - throw new Error( - 'Database schema generation requires specific configuration arguments as an array.', - ); - } + context.getGlobalContext('projectName') || 'Default Project Name'; + const databaseType = + context.getGlobalContext('databaseType') || 'PostgreSQL'; - const [dbRequirements] = args as DBSchemaArgs; + const dbRequirements = context.getNodeData('op:DATABASE_REQ'); this.logger.debug('Database requirements are provided.'); diff --git a/backend/src/build-system/handlers/file-manager/file-arch/index.ts b/backend/src/build-system/handlers/file-manager/file-arch/index.ts index 838c4dad..b35b130e 100644 --- a/backend/src/build-system/handlers/file-manager/file-arch/index.ts +++ b/backend/src/build-system/handlers/file-manager/file-arch/index.ts @@ -4,22 +4,24 @@ import { generateFileArchPrompt } from './prompt'; import { Logger } from '@nestjs/common'; import { extractJsonFromMarkdown } from 'src/build-system/utils/strings'; -export class FileArchGenerateHandler implements BuildHandler { - readonly id = 'op:FILE_ARCH::STATE:GENERATE'; +export class FileArchGenerateHandler implements BuildHandler { + readonly id = 'op:FILE:ARCH'; private readonly logger: Logger = new Logger('FileArchGenerateHandler'); // TODO: adding page by page analysis - async run(context: BuilderContext, args: unknown): Promise { + async run(context: BuilderContext): Promise> { this.logger.log('Generating File Architecture Document...'); - const fileStructure = args[0] as string; - const dataMapStruct = args[1] as string; + const fileStructure = context.getNodeData('op:FILE:STRUCT'); + // TODO: here should use datamap struct + const dataMapStruct = context.getNodeData('op:UX:DATAMAP:DOC'); + // TODO: adding page by page analysis if (!fileStructure || !dataMapStruct) { return { success: false, error: new Error( - 'Missing required parameters: fileStructure or pageByPageAnalysis', + 'Missing required parameters: fileStructure or dataMapStruct', ), }; } @@ -35,37 +37,53 @@ export class FileArchGenerateHandler implements BuildHandler { let jsonData = null; let retry = 0; const retryChances = 2; + while (!successBuild) { if (retry > retryChances) { - throw new Error( + this.logger.error( 'Failed to build virtual directory after multiple attempts', ); + return { + success: false, + error: new Error( + 'Failed to build virtual directory after multiple attempts', + ), + }; } + try { + fileArchContent = await context.model.chatSync( + { + content: prompt, + }, + 'gpt-4o-mini', + ); - fileArchContent = await context.model.chatSync( - { - content: prompt, - }, - 'gpt-4o-mini', - ); + // validation test + jsonData = extractJsonFromMarkdown(fileArchContent); + if (jsonData == null) { + retry += 1; + this.logger.error('Extract Json From Markdown fail'); + continue; + } - // validation test - jsonData = extractJsonFromMarkdown(fileArchContent); - if (jsonData == null) { - retry += 1; - this.logger.error('Extract Json From Markdown fail'); - continue; - } + // Validate the extracted JSON data + if (!this.validateJsonData(jsonData)) { + retry += 1; + this.logger.error('File architecture JSON validation failed'); + continue; + } - if (!this.validateJsonData(jsonData)) { - retry += 1; - this.logger.error('FileArchGenerate validateJsonData fail'); - continue; + successBuild = true; + } catch (error) { + this.logger.error('Error during JSON extraction or validation', error); + return { + success: false, + error: new Error('Error during JSON extraction or validation'), + }; } - this.logger.log(jsonData); - successBuild = true; } + this.logger.log('File architecture document generated successfully'); return { success: true, data: fileArchContent, @@ -75,7 +93,7 @@ export class FileArchGenerateHandler implements BuildHandler { /** * Validate the structure and content of the JSON data. * @param jsonData The JSON data to validate. - * @throws Error if validation fails. + * @returns A boolean indicating whether the JSON data is valid. */ private validateJsonData(jsonData: { files: Record; diff --git a/backend/src/build-system/handlers/file-manager/file-generate/index.ts b/backend/src/build-system/handlers/file-manager/file-generate/index.ts index 7fbb26ff..ad0b3a01 100644 --- a/backend/src/build-system/handlers/file-manager/file-generate/index.ts +++ b/backend/src/build-system/handlers/file-manager/file-generate/index.ts @@ -7,21 +7,29 @@ import { BuilderContext } from 'src/build-system/context'; import { BuildHandler, BuildResult } from 'src/build-system/types'; import { extractJsonFromMarkdown } from 'src/build-system/utils/strings'; import { getProjectPath } from 'src/config/common-path'; -import * as normalizePath from 'normalize-path'; +import normalizePath from 'normalize-path'; -export class FileGeneratorHandler implements BuildHandler { - readonly id = 'op:FILE_GENERATE::STATE:GENERATE'; +export class FileGeneratorHandler implements BuildHandler { + readonly id = 'op:FILE:GENERATE'; private readonly logger = new Logger('FileGeneratorHandler'); private virtualDir: VirtualDirectory; - async run(context: BuilderContext, args: unknown): Promise { + async run(context: BuilderContext): Promise> { this.virtualDir = context.virtualDirectory; - const fileArch = args[0] as string; - const uuid = context.getData('projectUUID'); + const fileArchDoc = context.getNodeData('op:FILE:ARCH'); + const uuid = context.getGlobalContext('projectUUID'); const projectSrcPath = getProjectPath(uuid); - this.generateFiles(JSON.stringify(fileArch, null, 2), projectSrcPath); + try { + await this.generateFiles(fileArchDoc, projectSrcPath); + } catch (error) { + this.logger.error('Error during file generation process', error); + return { + success: false, + error: new Error('Failed to generate files and dependencies.'), + }; + } return { success: true, @@ -37,31 +45,27 @@ export class FileGeneratorHandler implements BuildHandler { async generateFiles( markdownContent: string, projectSrcPath: string, - ): Promise<{ success: boolean; data: string }> { + ): Promise { const jsonData = extractJsonFromMarkdown(markdownContent); + // Build the dependency graph and detect cycles before any file operations const { graph, nodes } = this.buildDependencyGraph(jsonData); this.detectCycles(graph); - // Add virtual directory validation + // Validate files against the virtual directory structure this.validateAgainstVirtualDirectory(nodes); - // After validation and cycle detection, perform topological sort + // Perform topological sort for file generation const sortedFiles = this.getSortedFiles(graph, nodes); - // Generate files in the correct order + // Generate files in dependency order for (const file of sortedFiles) { const fullPath = normalizePath(path.resolve(projectSrcPath, file)); this.logger.log(`Generating file in dependency order: ${fullPath}`); - // TODO(allen) await this.createFile(fullPath); } this.logger.log('All files generated successfully.'); - return { - success: true, - data: 'Files and dependencies created successfully.', - }; } /** @@ -87,7 +91,7 @@ export class FileGeneratorHandler implements BuildHandler { } /** - * Detect cycles in the dependency graph before any file operations. + * Detect cycles in the dependency graph. * @param graph The dependency graph to check. * @throws Error if a cycle is detected. */ @@ -115,7 +119,7 @@ export class FileGeneratorHandler implements BuildHandler { ): string[] { const sortedFiles = toposort(graph).reverse(); - // Add any files that have no dependencies and weren't included in the sort + // Add any files with no dependencies Array.from(nodes).forEach((node) => { if (!sortedFiles.includes(node)) { sortedFiles.unshift(node); @@ -132,25 +136,21 @@ export class FileGeneratorHandler implements BuildHandler { */ private resolveDependency(currentFile: string, dependency: string): string { const currentDir = path.dirname(currentFile); - - // Check if the dependency is a file with an extension const hasExtension = path.extname(dependency).length > 0; - // If the dependency doesn't have an extension and is not CSS/JS, assume it's a TypeScript file if (!hasExtension) { dependency = path.join(dependency, 'index.ts'); } - // Resolve the dependency path relative to the current directory const resolvedPath = path.join(currentDir, dependency).replace(/\\/g, '/'); this.logger.log(`Resolved dependency: ${resolvedPath}`); return resolvedPath; } /** - * Validate that all files and dependencies exist in the virtual directory structure - * @param nodes Set of all files and dependencies - * @throws Error if any file or dependency is not found in the virtual directory + * Validate all files and dependencies against the virtual directory. + * @param nodes Set of all files and dependencies. + * @throws Error if any file or dependency is not valid. */ private validateAgainstVirtualDirectory(nodes: Set): void { const invalidFiles: string[] = []; diff --git a/backend/src/build-system/handlers/file-manager/file-structure/index.ts b/backend/src/build-system/handlers/file-manager/file-structure/index.ts index 9d17d06e..98b4e5e8 100644 --- a/backend/src/build-system/handlers/file-manager/file-structure/index.ts +++ b/backend/src/build-system/handlers/file-manager/file-structure/index.ts @@ -1,30 +1,14 @@ -import { BuildHandler, BuildResult } from 'src/build-system/types'; +import { BuildHandler, BuildOpts, BuildResult } from 'src/build-system/types'; import { BuilderContext } from 'src/build-system/context'; import { prompts } from './prompt'; import { Logger } from '@nestjs/common'; -/** - * Defines the expected order and types of arguments for FileStructureHandler. - * - * Expected argument order: - * 0 - sitemapDoc: string - * 1 - dataAnalysisDoc: string - * 2 - framework: string - * 3 - projectPart: 'frontend' | 'backend' - */ -type FileStructureArgs = [ - sitemapDoc: string, - dataAnalysisDoc: string, - framework: string, - projectPart: 'frontend' | 'backend', -]; - /** * FileStructureHandler is responsible for generating the project's file and folder structure * based on the provided documentation. */ -export class FileStructureHandler implements BuildHandler { - readonly id = 'op:FSTRUCT::STATE:GENERATE'; +export class FileStructureHandler implements BuildHandler { + readonly id = 'op:FILE:STRUCT'; private readonly logger: Logger = new Logger('FileStructureHandler'); /** @@ -33,24 +17,22 @@ export class FileStructureHandler implements BuildHandler { * @param args - The variadic arguments required for generating the file structure. * @returns A BuildResult containing the generated file structure JSON and related data. */ - async run(context: BuilderContext, ...args: any[]): Promise { + async run( + context: BuilderContext, + opts?: BuildOpts, + ): Promise> { this.logger.log('Generating File Structure Document...'); // Retrieve projectName from context const projectName = - context.getData('projectName') || 'Default Project Name'; + context.getGlobalContext('projectName') || 'Default Project Name'; this.logger.debug(`Project Name: ${projectName}`); - // Validate and extract args - if (!args || !Array.isArray(args)) { - throw new Error( - 'File structure generation requires specific configuration arguments as an array.', - ); - } - - // Destructure arguments with type assertion - const [sitemapDoc, dataAnalysisDoc, framework, projectPart] = - args as FileStructureArgs; + const sitemapDoc = context.getNodeData('op:UX:SMD'); + const datamapDoc = context.getNodeData('op:UX:DATAMAP:DOC'); + // TODO: make sure passing this parameter is correct + const projectPart = opts.projectPart ?? 'frontend'; + const framework = context.getGlobalContext('framework'); // Validate required arguments if (!sitemapDoc || typeof sitemapDoc !== 'string') { @@ -58,9 +40,9 @@ export class FileStructureHandler implements BuildHandler { 'The first argument (sitemapDoc) is required and must be a string.', ); } - if (!dataAnalysisDoc || typeof dataAnalysisDoc !== 'string') { + if (!datamapDoc || typeof datamapDoc !== 'string') { throw new Error( - 'The second argument (dataAnalysisDoc) is required and must be a string.', + 'The second argument (datamapDoc) is required and must be a string.', ); } if (!framework || typeof framework !== 'string') { @@ -86,7 +68,7 @@ export class FileStructureHandler implements BuildHandler { const prompt = prompts.generateCommonFileStructurePrompt( projectName, sitemapDoc, - dataAnalysisDoc, + datamapDoc, framework, projectPart, ); diff --git a/backend/src/build-system/handlers/product-manager/product-requirements-document/prd.ts b/backend/src/build-system/handlers/product-manager/product-requirements-document/prd.ts index bd65555c..baf10905 100644 --- a/backend/src/build-system/handlers/product-manager/product-requirements-document/prd.ts +++ b/backend/src/build-system/handlers/product-manager/product-requirements-document/prd.ts @@ -5,16 +5,17 @@ import { ModelProvider } from 'src/common/model-provider'; import { Logger } from '@nestjs/common'; export class PRDHandler implements BuildHandler { - readonly id = 'op:PRD::STATE:GENERATE'; + readonly id = 'op:PRD'; readonly logger: Logger = new Logger('PRDHandler'); async run(context: BuilderContext): Promise { this.logger.log('Generating PRD...'); // Extract project data from the context const projectName = - context.getData('projectName') || 'Default Project Name'; - const description = context.getData('description') || 'Default Description'; - const platform = context.getData('platform') || 'Default Platform'; + context.getGlobalContext('projectName') || 'Default Project Name'; + const description = + context.getGlobalContext('description') || 'Default Description'; + const platform = context.getGlobalContext('platform') || 'Default Platform'; // Generate the prompt dynamically const prompt = prompts.generatePRDPrompt( diff --git a/backend/src/build-system/handlers/project-init.ts b/backend/src/build-system/handlers/project-init.ts index 39eed570..88b12746 100644 --- a/backend/src/build-system/handlers/project-init.ts +++ b/backend/src/build-system/handlers/project-init.ts @@ -13,7 +13,7 @@ export class ProjectInitHandler implements BuildHandler { Platform: 'Web', path: '/path/to/project', }; - context.setData('projectConfig', result); + context.setGlobalContext('projectConfig', result); return { success: true, data: result, diff --git a/backend/src/build-system/handlers/ux/datamap/index.ts b/backend/src/build-system/handlers/ux/datamap/index.ts index 908ad2f0..0eab70d9 100644 --- a/backend/src/build-system/handlers/ux/datamap/index.ts +++ b/backend/src/build-system/handlers/ux/datamap/index.ts @@ -3,21 +3,24 @@ import { BuilderContext } from 'src/build-system/context'; import { ModelProvider } from 'src/common/model-provider'; import { prompts } from './prompt'; -export class UXDatamapHandler implements BuildHandler { - readonly id = 'op:UX_DATAMAP::STATE:GENERATE'; +/** + * Handler for generating the UX Data Map document. + */ +export class UXDatamapHandler implements BuildHandler { + readonly id = 'op:UX:DATAMAP:DOC'; - async run(context: BuilderContext, args: unknown): Promise { + async run(context: BuilderContext): Promise> { console.log('Generating UX Data Map Document...'); - // extract relevant data from the context + // Extract relevant data from the context const projectName = - context.getData('projectName') || 'Default Project Name'; + context.getGlobalContext('projectName') || 'Default Project Name'; + const sitemapDoc = context.getNodeData('op:UX:SMD'); const prompt = prompts.generateUXDataMapPrompt( projectName, - args as string, - // TODO: change later - 'web', + sitemapDoc, + 'web', // TODO: change platform dynamically if needed ); const uxDatamapContent = await context.model.chatSync( @@ -26,6 +29,7 @@ export class UXDatamapHandler implements BuildHandler { }, 'gpt-4o-mini', ); + return { success: true, data: uxDatamapContent, diff --git a/backend/src/build-system/handlers/ux/sitemap-document/prompt/prompt.ts b/backend/src/build-system/handlers/ux/sitemap-document/prompt.ts similarity index 100% rename from backend/src/build-system/handlers/ux/sitemap-document/prompt/prompt.ts rename to backend/src/build-system/handlers/ux/sitemap-document/prompt.ts diff --git a/backend/src/build-system/handlers/ux/sitemap-document/uxsmd.ts b/backend/src/build-system/handlers/ux/sitemap-document/uxsmd.ts index 42d6fce6..6fd8ac55 100644 --- a/backend/src/build-system/handlers/ux/sitemap-document/uxsmd.ts +++ b/backend/src/build-system/handlers/ux/sitemap-document/uxsmd.ts @@ -1,25 +1,26 @@ import { BuildHandler, BuildResult } from 'src/build-system/types'; import { BuilderContext } from 'src/build-system/context'; -import { prompts } from './prompt/prompt'; +import { prompts } from './prompt'; import { ModelProvider } from 'src/common/model-provider'; import { Logger } from '@nestjs/common'; -export class UXSMDHandler implements BuildHandler { - readonly id = 'op:UXSMD::STATE:GENERATE'; +export class UXSMDHandler implements BuildHandler { + readonly id = 'op:UX:SMD'; readonly logger: Logger = new Logger('UXSMDHandler'); - async run(context: BuilderContext, args: unknown): Promise { + async run(context: BuilderContext): Promise> { this.logger.log('Generating UXSMD...'); // Extract project data from the context const projectName = - context.getData('projectName') || 'Default Project Name'; - const platform = context.getData('platform') || 'Default Platform'; + context.getGlobalContext('projectName') || 'Default Project Name'; + const platform = context.getGlobalContext('platform') || 'Default Platform'; + const prdContent = context.getNodeData('op:PRD'); // Generate the prompt dynamically const prompt = prompts.generateUxsmdrompt( projectName, - args as string, + prdContent, platform, ); @@ -27,8 +28,9 @@ export class UXSMDHandler implements BuildHandler { const uxsmdContent = await this.generateUXSMDFromLLM(prompt); // Store the generated document in the context - context.setData('uxsmdDocument', uxsmdContent); + context.setGlobalContext('uxsmdDocument', uxsmdContent); + // Return the generated document return { success: true, data: uxsmdContent, @@ -37,10 +39,9 @@ export class UXSMDHandler implements BuildHandler { private async generateUXSMDFromLLM(prompt: string): Promise { const modelProvider = ModelProvider.getInstance(); - const model = 'gpt-4o-mini'; - const prdContent = modelProvider.chatSync( + const uxsmdContent = await modelProvider.chatSync( { content: prompt, }, @@ -48,6 +49,6 @@ export class UXSMDHandler implements BuildHandler { ); this.logger.log('Received full UXSMD content from LLM server.'); - return prdContent; + return uxsmdContent; } } diff --git a/backend/src/build-system/handlers/ux/sitemap-structure/index.ts b/backend/src/build-system/handlers/ux/sitemap-structure/index.ts index 8ce2bfaf..6d08cead 100644 --- a/backend/src/build-system/handlers/ux/sitemap-structure/index.ts +++ b/backend/src/build-system/handlers/ux/sitemap-structure/index.ts @@ -5,20 +5,19 @@ import { prompts } from './prompt'; import { Logger } from '@nestjs/common'; // UXSMS: UX Sitemap Structure -export class UXSitemapStructureHandler implements BuildHandler { - readonly id = 'op:UXSMS::STATE:GENERATE'; +export class UXSitemapStructureHandler implements BuildHandler { + readonly id = 'op:UX:SMS'; readonly logger = new Logger('UXSitemapStructureHandler'); - async run(context: BuilderContext, args: unknown): Promise { + async run(context: BuilderContext): Promise> { this.logger.log('Generating UX Structure Document...'); // extract relevant data from the context const projectName = - context.getData('projectName') || 'Default Project Name'; + context.getGlobalContext('projectName') || 'Default Project Name'; + const sitemapDoc = context.getNodeData('op:UX:SMD'); - const sitemap = args[0] as string; - - if (!sitemap) { + if (!sitemapDoc) { return { success: false, error: new Error('Missing required parameters: sitemap'), @@ -27,47 +26,46 @@ export class UXSitemapStructureHandler implements BuildHandler { const prompt = prompts.generateUXSiteMapStructrePrompt( projectName, - JSON.stringify(sitemap, null, 2), - // TODO: change later - 'web', + sitemapDoc, + 'web', // TODO: Change platform dynamically if necessary ); this.logger.log(prompt); + const uxStructureContent = await context.model.chatSync( { content: prompt, }, 'gpt-4o-mini', ); + return { success: true, data: uxStructureContent, }; } } - -export class Level2UXSitemapStructureHandler implements BuildHandler { - readonly id = 'op:LEVEL2_UXSMS::STATE:GENERATE'; +export class Level2UXSitemapStructureHandler implements BuildHandler { + readonly id = 'op:UX:SMS:LEVEL2'; readonly logger = new Logger('Level2UXSitemapStructureHandler'); - async run(context: BuilderContext, args: unknown): Promise { + async run(context: BuilderContext): Promise> { this.logger.log('Generating Level 2 UX Sitemap Structure Document...'); - // Extract necessary data from the context - const { projectName, sitemapDoc, uxStructureDoc } = args as { - projectName: string; - sitemapDoc: string; - uxStructureDoc: string; - }; + const projectName = + context.getGlobalContext('projectName') || 'Default Project Name'; + const sitemapDoc = context.getNodeData('op:UX:SMS'); + const uxStructureDoc = context.getNodeData('op:UX:SMS'); - // Ensure the UX Structure Document exists if (!projectName || !sitemapDoc || !uxStructureDoc) { - throw new Error( - 'Missing required arguments: projectName, sitemapDoc, or uxStructureDoc.', - ); + return { + success: false, + data: 'Missing required arguments: projectName, sitemapDoc, or uxStructureDoc.', + }; } // Extract sections from the UX Structure Document const sections = this.extractAllSections(uxStructureDoc); + if (sections.length === 0) { this.logger.error( 'No valid sections found in the UX Structure Document.', @@ -90,7 +88,6 @@ export class Level2UXSitemapStructureHandler implements BuildHandler { 'web', // TODO: Replace with dynamic platform if necessary ); - // Generate refined UX Structure content const refinedContent = await modelProvider.chatSync( { content: prompt }, 'gpt-4o-mini', diff --git a/backend/src/build-system/types.ts b/backend/src/build-system/types.ts index 18cfb767..8e1cb041 100644 --- a/backend/src/build-system/types.ts +++ b/backend/src/build-system/types.ts @@ -1,5 +1,6 @@ import { ModelProvider } from 'src/common/model-provider'; import { BuilderContext } from './context'; +import { BuildOptions } from 'typescript'; export type BuildNodeType = | 'PROJECT_SETUP' @@ -23,6 +24,7 @@ export interface BuildBase { name?: string; description?: string; requires?: string[]; + options?: BuildOpts; } export interface BuildNode extends BuildBase { @@ -44,6 +46,9 @@ export interface BuildSequence { version: string; name: string; description?: string; + //TODO: adding dependencies infos list here + //TODO: adding type for database maybe + databaseType?: string; steps: BuildStep[]; } @@ -61,9 +66,9 @@ export interface BuildContext { pendingNodes: Set; } -export interface BuildResult { +export interface BuildResult { success: boolean; - data?: any; + data?: T; error?: Error; } @@ -74,7 +79,10 @@ export interface BuildExecutionState { waiting: Set; } -export interface BuildHandler { +export interface BuildOpts { + projectPart?: 'frontend' | 'backend'; +} +export interface BuildHandler { // Unique identifier for the handler id: string; @@ -84,5 +92,27 @@ export interface BuildHandler { * @param model model provider for the build * @param args the request arguments */ - run(context: BuilderContext, ...args: any[]): Promise; + run(context: BuilderContext, opts?: BuildOpts): Promise>; +} + +export interface NodeOutputMap { + 'op:DATABASE_REQ': string; + 'op:PRD': string; + 'op:UX:SMD': string; + 'op:UX:SMS': string; + 'op:UX:SMS:LEVEL2': string; + 'op:UX:DATAMAP:DOC': string; + 'op:FILE:STRUCT': string; + 'op:FILE:ARCH': string; + 'op:FILE:GENERATE': string; + 'op:BACKEND:CODE': string; + 'op:BACKEND:REQ': { + overview: string; + implementation: string; + config: { + language: string; + framework: string; + packages: Record; + }; + }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4fdd4069..08d0129f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,10 +14,10 @@ importers: devDependencies: '@typescript-eslint/eslint-plugin': specifier: ^8.0.0 - version: 8.18.0(@typescript-eslint/parser@8.18.0)(eslint@8.57.1)(typescript@5.6.2) + version: 8.18.1(@typescript-eslint/parser@8.18.1)(eslint@8.57.1)(typescript@5.6.2) '@typescript-eslint/parser': specifier: ^8.0.0 - version: 8.18.0(eslint@8.57.1)(typescript@5.6.2) + version: 8.18.1(eslint@8.57.1)(typescript@5.6.2) eslint: specifier: ^8.57.1 version: 8.57.1 @@ -156,10 +156,10 @@ importers: version: 6.0.2 '@typescript-eslint/eslint-plugin': specifier: ^8.0.0 - version: 8.18.0(@typescript-eslint/parser@8.18.0)(eslint@8.57.1)(typescript@5.7.2) + version: 8.18.1(@typescript-eslint/parser@8.18.1)(eslint@8.57.1)(typescript@5.7.2) '@typescript-eslint/parser': specifier: ^8.0.0 - version: 8.18.0(eslint@8.57.1)(typescript@5.7.2) + version: 8.18.1(eslint@8.57.1)(typescript@5.7.2) eslint: specifier: ^8.57.1 version: 8.57.1 @@ -205,7 +205,7 @@ importers: dependencies: '@apollo/client': specifier: ^3.11.8 - version: 3.12.3(@types/react@18.3.16)(graphql-ws@5.16.0)(graphql@16.10.0)(react-dom@18.3.1)(react@18.3.1)(subscriptions-transport-ws@0.11.0) + version: 3.12.3(@types/react@18.3.17)(graphql-ws@5.16.0)(graphql@16.10.0)(react-dom@18.3.1)(react@18.3.1)(subscriptions-transport-ws@0.11.0) '@emoji-mart/data': specifier: ^1.2.1 version: 1.2.1 @@ -226,37 +226,37 @@ importers: version: 10.4.15(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@radix-ui/react-avatar': specifier: ^1.1.0 - version: 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-dialog': specifier: ^1.1.1 - version: 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-dropdown-menu': specifier: ^2.1.1 - version: 2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.2(react@18.3.1) '@radix-ui/react-label': specifier: ^2.1.0 - version: 2.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 2.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-popover': specifier: ^1.1.1 - version: 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-scroll-area': specifier: ^1.2.0 - version: 1.2.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 1.2.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-select': specifier: ^2.1.1 - version: 2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-separator': specifier: ^1.1.0 - version: 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.1.0 - version: 1.1.1(@types/react@18.3.16)(react@18.3.1) + version: 1.1.1(@types/react@18.3.17)(react@18.3.1) '@radix-ui/react-tooltip': specifier: ^1.1.2 - version: 1.1.5(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 1.1.5(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@types/dom-speech-recognition': specifier: ^0.0.4 version: 0.0.4 @@ -271,7 +271,7 @@ importers: version: 5.6.0 framer-motion: specifier: ^11.5.6 - version: 11.14.4(react-dom@18.3.1)(react@18.3.1) + version: 11.15.0(react-dom@18.3.1)(react@18.3.1) graphql: specifier: ^16.9.0 version: 16.10.0 @@ -304,13 +304,13 @@ importers: version: 7.54.1(react@18.3.1) react-markdown: specifier: ^9.0.1 - version: 9.0.1(@types/react@18.3.16)(react@18.3.1) + version: 9.0.1(@types/react@18.3.17)(react@18.3.1) react-resizable-panels: specifier: ^2.1.3 version: 2.1.7(react-dom@18.3.1)(react@18.3.1) react-textarea-autosize: specifier: ^8.5.3 - version: 8.5.6(@types/react@18.3.16)(react@18.3.1) + version: 8.5.6(@types/react@18.3.17)(react@18.3.1) remark-gfm: specifier: ^4.0.0 version: 4.0.0 @@ -337,7 +337,7 @@ importers: version: 3.24.1 zustand: specifier: ^5.0.0-rc.2 - version: 5.0.2(@types/react@18.3.16)(react@18.3.1) + version: 5.0.2(@types/react@18.3.17)(react@18.3.1) devDependencies: '@0no-co/graphqlsp': specifier: ^1.12.16 @@ -368,7 +368,7 @@ importers: version: 6.6.3 '@testing-library/react': specifier: ^16.0.1 - version: 16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) + version: 16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) '@types/jest': specifier: ^29.5.14 version: 29.5.14 @@ -377,10 +377,10 @@ importers: version: 22.10.2 '@types/react': specifier: ^18.3.8 - version: 18.3.16 + version: 18.3.17 '@types/react-dom': specifier: ^18.3.0 - version: 18.3.5(@types/react@18.3.16) + version: 18.3.5(@types/react@18.3.17) '@types/uuid': specifier: ^10.0.0 version: 10.0.0 @@ -441,10 +441,10 @@ importers: version: 16.18.122 '@typescript-eslint/eslint-plugin': specifier: ^8.0.0 - version: 8.18.0(@typescript-eslint/parser@8.18.0)(eslint@8.57.1)(typescript@5.7.2) + version: 8.18.1(@typescript-eslint/parser@8.18.1)(eslint@8.57.1)(typescript@5.7.2) '@typescript-eslint/parser': specifier: ^8.0.0 - version: 8.18.0(eslint@8.57.1)(typescript@5.7.2) + version: 8.18.1(eslint@8.57.1)(typescript@5.7.2) eslint: specifier: ^8.57.1 version: 8.57.1 @@ -583,7 +583,7 @@ packages: graphql: 16.10.0 dev: false - /@apollo/client@3.12.3(@types/react@18.3.16)(graphql-ws@5.16.0)(graphql@16.10.0)(react-dom@18.3.1)(react@18.3.1)(subscriptions-transport-ws@0.11.0): + /@apollo/client@3.12.3(@types/react@18.3.17)(graphql-ws@5.16.0)(graphql@16.10.0)(react-dom@18.3.1)(react@18.3.1)(subscriptions-transport-ws@0.11.0): resolution: {integrity: sha512-KZ5zymRdb8bMbGUb1wP2U04ff7qIGgaC1BCdCVC+IPFiXkxEhHBc5fDEQOwAUT+vUo9KbBh3g7QK/JCOswn59w==} peerDependencies: graphql: ^15.0.0 || ^16.0.0 @@ -613,7 +613,7 @@ packages: prop-types: 15.8.1 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rehackt: 0.1.0(@types/react@18.3.16)(react@18.3.1) + rehackt: 0.1.0(@types/react@18.3.17)(react@18.3.1) response-iterator: 0.2.6 subscriptions-transport-ws: 0.11.0(graphql@16.10.0) symbol-observable: 4.0.0 @@ -4485,7 +4485,7 @@ packages: resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} dev: false - /@radix-ui/react-arrow@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-arrow@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==} peerDependencies: '@types/react': '*' @@ -4498,14 +4498,14 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-avatar@1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-avatar@1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-GaC7bXQZ5VgZvVvsJ5mu/AEbjYLnhhkoidOboC50Z6FFlLA03wG2ianUoH+zgDQ31/9gCF59bE4+2bBgTyMiig==} peerDependencies: '@types/react': '*' @@ -4518,17 +4518,17 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-collection@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-collection@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==} peerDependencies: '@types/react': '*' @@ -4541,17 +4541,17 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-compose-refs@1.1.1(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-compose-refs@1.1.1(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} peerDependencies: '@types/react': '*' @@ -4560,11 +4560,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-context@1.1.1(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-context@1.1.1(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} peerDependencies: '@types/react': '*' @@ -4573,11 +4573,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-dialog@1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-dialog@1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-ujGvqQNkZ0J7caQyl8XuZRj2/TIrYcOGwqz5TeD1OMcCdfBuEMP0D12ve+8J5F9XuNUth3FAKFWo/wt0E/GJrQ==} peerDependencies: '@types/react': '*' @@ -4591,26 +4591,26 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.6.0(@types/react@18.3.16)(react@18.3.1) + react-remove-scroll: 2.6.0(@types/react@18.3.17)(react@18.3.1) dev: false - /@radix-ui/react-direction@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-direction@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} peerDependencies: '@types/react': '*' @@ -4619,11 +4619,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-dismissable-layer@1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-dismissable-layer@1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-kEHnlhv7wUggvhuJPkyw4qspXLJOdYoAP4dO2c8ngGuXTq1w/HZp1YeVB+NQ2KbH1iEG+pvOCGYSqh9HZOz6hg==} peerDependencies: '@types/react': '*' @@ -4637,17 +4637,17 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-dropdown-menu@2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-dropdown-menu@2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-eKyAfA9e4HOavzyGJC6kiDIlHMPzAU0zqSqTg+VwS0Okvb9nkTo7L4TugkCUqM3I06ciSpdtYQ73cgB7tyUgVw==} peerDependencies: '@types/react': '*' @@ -4661,19 +4661,19 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-menu': 2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-menu': 2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-focus-guards@1.1.1(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-focus-guards@1.1.1(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} peerDependencies: '@types/react': '*' @@ -4682,11 +4682,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-focus-scope@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-focus-scope@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==} peerDependencies: '@types/react': '*' @@ -4699,11 +4699,11 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false @@ -4716,7 +4716,7 @@ packages: react: 18.3.1 dev: false - /@radix-ui/react-id@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-id@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: '@types/react': '*' @@ -4725,12 +4725,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-label@2.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-label@2.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==} peerDependencies: '@types/react': '*' @@ -4743,14 +4743,14 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-menu@2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-menu@2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-wY5SY6yCiJYP+DMIy7RrjF4shoFpB9LJltliVwejBm8T2yepWDJgKBhIFYOGWYR/lFHOCtbstN9duZFu6gmveQ==} peerDependencies: '@types/react': '*' @@ -4764,30 +4764,30 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.6.0(@types/react@18.3.16)(react@18.3.1) + react-remove-scroll: 2.6.0(@types/react@18.3.17)(react@18.3.1) dev: false - /@radix-ui/react-popover@1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-popover@1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-MBDKFwRe6fi0LT8m/Jl4V8J3WbS/UfXJtsgg8Ym5w5AyPG3XfHH4zhBp1P8HmZK83T8J7UzVm6/JpDE3WMl1Dw==} peerDependencies: '@types/react': '*' @@ -4801,27 +4801,27 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.6.0(@types/react@18.3.16)(react@18.3.1) + react-remove-scroll: 2.6.0(@types/react@18.3.17)(react@18.3.1) dev: false - /@radix-ui/react-popper@1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-popper@1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==} peerDependencies: '@types/react': '*' @@ -4835,22 +4835,22 @@ packages: optional: true dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-arrow': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.16)(react@18.3.1) + '@radix-ui/react-arrow': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.17)(react@18.3.1) '@radix-ui/rect': 1.1.0 - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-portal@1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-portal@1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==} peerDependencies: '@types/react': '*' @@ -4863,15 +4863,15 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-presence@1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-presence@1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} peerDependencies: '@types/react': '*' @@ -4884,15 +4884,15 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-primitive@2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-primitive@2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==} peerDependencies: '@types/react': '*' @@ -4905,14 +4905,14 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-slot': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-roving-focus@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-roving-focus@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-QE1RoxPGJ/Nm8Qmk0PxP8ojmoaS67i0s7hVssS7KuI2FQoc/uzVlZsqKfQvxPE6D8hICCPHJ4D88zNhT3OOmkw==} peerDependencies: '@types/react': '*' @@ -4926,21 +4926,21 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-scroll-area@1.2.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-scroll-area@1.2.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==} peerDependencies: '@types/react': '*' @@ -4955,20 +4955,20 @@ packages: dependencies: '@radix-ui/number': 1.1.0 '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-select@2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-select@2.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-tlLwaewTfrKetiex8iW9wwME/qrYlzlH0qcgYmos7xS54MO00SiPHasLoAykg/yVrjf41GQptPPi4oXzrP+sgg==} peerDependencies: '@types/react': '*' @@ -4983,32 +4983,32 @@ packages: dependencies: '@radix-ui/number': 1.1.0 '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.6.0(@types/react@18.3.16)(react@18.3.1) + react-remove-scroll: 2.6.0(@types/react@18.3.17)(react@18.3.1) dev: false - /@radix-ui/react-separator@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-separator@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-RRiNRSrD8iUiXriq/Y5n4/3iE8HzqgLHsusUSg5jVpU2+3tqcUFPJXHDymwEypunc2sWxDUS3UC+rkZRlHedsw==} peerDependencies: '@types/react': '*' @@ -5021,14 +5021,14 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-slot@1.1.1(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-slot@1.1.1(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} peerDependencies: '@types/react': '*' @@ -5037,12 +5037,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-tooltip@1.1.5(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-tooltip@1.1.5(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-IucoQPcK5nwUuztaxBQvudvYwH58wtRcJlv1qvaMSyIbL9dEBfFN0vRf/D8xDbu6HmAJLlNGty4z8Na+vIqe9Q==} peerDependencies: '@types/react': '*' @@ -5056,24 +5056,24 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.1.1(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} peerDependencies: '@types/react': '*' @@ -5082,11 +5082,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} peerDependencies: '@types/react': '*' @@ -5095,12 +5095,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} peerDependencies: '@types/react': '*' @@ -5109,12 +5109,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} peerDependencies: '@types/react': '*' @@ -5123,11 +5123,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-use-previous@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-use-previous@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} peerDependencies: '@types/react': '*' @@ -5136,11 +5136,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-use-rect@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-use-rect@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} peerDependencies: '@types/react': '*' @@ -5150,11 +5150,11 @@ packages: optional: true dependencies: '@radix-ui/rect': 1.1.0 - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-use-size@1.1.0(@types/react@18.3.16)(react@18.3.1): + /@radix-ui/react-use-size@1.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} peerDependencies: '@types/react': '*' @@ -5163,12 +5163,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.16)(react@18.3.1) - '@types/react': 18.3.16 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.17)(react@18.3.1) + '@types/react': 18.3.17 react: 18.3.1 dev: false - /@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==} peerDependencies: '@types/react': '*' @@ -5181,9 +5181,9 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false @@ -5350,7 +5350,7 @@ packages: redent: 3.0.0 dev: true - /@testing-library/react@16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.5)(@types/react@18.3.16)(react-dom@18.3.1)(react@18.3.1): + /@testing-library/react@16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.5)(@types/react@18.3.17)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==} engines: {node: '>=18'} peerDependencies: @@ -5367,8 +5367,8 @@ packages: dependencies: '@babel/runtime': 7.26.0 '@testing-library/dom': 10.4.0 - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/react@18.3.16) + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: true @@ -5690,15 +5690,15 @@ packages: /@types/range-parser@1.2.7: resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - /@types/react-dom@18.3.5(@types/react@18.3.16): + /@types/react-dom@18.3.5(@types/react@18.3.17): resolution: {integrity: sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==} peerDependencies: '@types/react': ^18.0.0 dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 - /@types/react@18.3.16: - resolution: {integrity: sha512-oh8AMIC4Y2ciKufU8hnKgs+ufgbA/dhPTACaZPM86AbwX9QwnFtSoPWEeRUj8fge+v6kFt78BXcDhAU1SrrAsw==} + /@types/react@18.3.17: + resolution: {integrity: sha512-opAQ5no6LqJNo9TqnxBKsgnkIYHozW9KSTlFVoSUJYh1Fl/sswkEoqIugRSm7tbh6pABtYjGAjW+GOS23j8qbw==} dependencies: '@types/prop-types': 15.7.14 csstype: 3.1.3 @@ -5781,8 +5781,8 @@ packages: '@types/yargs-parser': 21.0.3 dev: true - /@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0)(eslint@8.57.1)(typescript@5.6.2): - resolution: {integrity: sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==} + /@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1)(eslint@8.57.1)(typescript@5.6.2): + resolution: {integrity: sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -5790,11 +5790,11 @@ packages: typescript: '>=4.8.4 <5.8.0' dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.6.2) - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/type-utils': 8.18.0(eslint@8.57.1)(typescript@5.6.2) - '@typescript-eslint/utils': 8.18.0(eslint@8.57.1)(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/type-utils': 8.18.1(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/utils': 8.18.1(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/visitor-keys': 8.18.1 eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 @@ -5805,8 +5805,8 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0)(eslint@8.57.1)(typescript@5.7.2): - resolution: {integrity: sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==} + /@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1)(eslint@8.57.1)(typescript@5.7.2): + resolution: {integrity: sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -5814,11 +5814,11 @@ packages: typescript: '>=4.8.4 <5.8.0' dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/type-utils': 8.18.0(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.0(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/type-utils': 8.18.1(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.1(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.1 eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 @@ -5829,17 +5829,17 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.6.2): - resolution: {integrity: sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==} + /@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.6.2): + resolution: {integrity: sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' dependencies: - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.6.2) + '@typescript-eslint/visitor-keys': 8.18.1 debug: 4.4.0(supports-color@5.5.0) eslint: 8.57.1 typescript: 5.6.2 @@ -5847,17 +5847,17 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2): - resolution: {integrity: sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==} + /@typescript-eslint/parser@8.18.1(eslint@8.57.1)(typescript@5.7.2): + resolution: {integrity: sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' dependencies: - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.1 debug: 4.4.0(supports-color@5.5.0) eslint: 8.57.1 typescript: 5.7.2 @@ -5865,23 +5865,23 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager@8.18.0: - resolution: {integrity: sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==} + /@typescript-eslint/scope-manager@8.18.1: + resolution: {integrity: sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/visitor-keys': 8.18.1 dev: true - /@typescript-eslint/type-utils@8.18.0(eslint@8.57.1)(typescript@5.6.2): - resolution: {integrity: sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==} + /@typescript-eslint/type-utils@8.18.1(eslint@8.57.1)(typescript@5.6.2): + resolution: {integrity: sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' dependencies: - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.6.2) - '@typescript-eslint/utils': 8.18.0(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.6.2) + '@typescript-eslint/utils': 8.18.1(eslint@8.57.1)(typescript@5.6.2) debug: 4.4.0(supports-color@5.5.0) eslint: 8.57.1 ts-api-utils: 1.4.3(typescript@5.6.2) @@ -5890,15 +5890,15 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@8.18.0(eslint@8.57.1)(typescript@5.7.2): - resolution: {integrity: sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==} + /@typescript-eslint/type-utils@8.18.1(eslint@8.57.1)(typescript@5.7.2): + resolution: {integrity: sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' dependencies: - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.1(eslint@8.57.1)(typescript@5.7.2) debug: 4.4.0(supports-color@5.5.0) eslint: 8.57.1 ts-api-utils: 1.4.3(typescript@5.7.2) @@ -5907,19 +5907,19 @@ packages: - supports-color dev: true - /@typescript-eslint/types@8.18.0: - resolution: {integrity: sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==} + /@typescript-eslint/types@8.18.1: + resolution: {integrity: sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /@typescript-eslint/typescript-estree@8.18.0(typescript@5.6.2): - resolution: {integrity: sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==} + /@typescript-eslint/typescript-estree@8.18.1(typescript@5.6.2): + resolution: {integrity: sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.8.0' dependencies: - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/visitor-keys': 8.18.1 debug: 4.4.0(supports-color@5.5.0) fast-glob: 3.3.2 is-glob: 4.0.3 @@ -5931,14 +5931,14 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@8.18.0(typescript@5.7.2): - resolution: {integrity: sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==} + /@typescript-eslint/typescript-estree@8.18.1(typescript@5.7.2): + resolution: {integrity: sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.8.0' dependencies: - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/visitor-keys': 8.18.1 debug: 4.4.0(supports-color@5.5.0) fast-glob: 3.3.2 is-glob: 4.0.3 @@ -5950,45 +5950,45 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@8.18.0(eslint@8.57.1)(typescript@5.6.2): - resolution: {integrity: sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==} + /@typescript-eslint/utils@8.18.1(eslint@8.57.1)(typescript@5.6.2): + resolution: {integrity: sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.6.2) + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.6.2) eslint: 8.57.1 typescript: 5.6.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@8.18.0(eslint@8.57.1)(typescript@5.7.2): - resolution: {integrity: sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==} + /@typescript-eslint/utils@8.18.1(eslint@8.57.1)(typescript@5.7.2): + resolution: {integrity: sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) eslint: 8.57.1 typescript: 5.7.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/visitor-keys@8.18.0: - resolution: {integrity: sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==} + /@typescript-eslint/visitor-keys@8.18.1: + resolution: {integrity: sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/types': 8.18.1 eslint-visitor-keys: 4.2.0 dev: true @@ -6475,7 +6475,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 - is-array-buffer: 3.0.4 + is-array-buffer: 3.0.5 dev: true /array-flatten@1.1.1: @@ -6567,7 +6567,7 @@ packages: es-abstract: 1.23.6 es-errors: 1.3.0 get-intrinsic: 1.2.6 - is-array-buffer: 3.0.4 + is-array-buffer: 3.0.5 dev: true /asap@2.0.6: @@ -6868,7 +6868,7 @@ packages: hasBin: true dependencies: caniuse-lite: 1.0.30001689 - electron-to-chromium: 1.5.73 + electron-to-chromium: 1.5.74 node-releases: 2.0.19 update-browserslist-db: 1.1.1(browserslist@4.24.3) @@ -7940,8 +7940,8 @@ packages: jake: 10.9.2 dev: true - /electron-to-chromium@1.5.73: - resolution: {integrity: sha512-8wGNxG9tAG5KhGd3eeA0o6ixhiNdgr0DcHWm85XPCphwZgD1lIEoi6t3VERayWao7SF7AAZTw6oARGJeVjH8Kg==} + /electron-to-chromium@1.5.74: + resolution: {integrity: sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==} /emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -8054,7 +8054,7 @@ packages: has-symbols: 1.1.0 hasown: 2.0.2 internal-slot: 1.1.0 - is-array-buffer: 3.0.4 + is-array-buffer: 3.0.5 is-callable: 1.2.7 is-data-view: 1.0.2 is-negative-zero: 2.0.3 @@ -8194,12 +8194,12 @@ packages: dependencies: '@next/eslint-plugin-next': 14.2.13 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 8.18.0(@typescript-eslint/parser@8.18.0)(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/eslint-plugin': 8.18.1(@typescript-eslint/parser@8.18.1)(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.7.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.2(eslint@8.57.1) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1) @@ -8246,7 +8246,7 @@ packages: debug: 4.4.0(supports-color@5.5.0) enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.3.0 @@ -8256,7 +8256,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): + /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: @@ -8277,7 +8277,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.7.2) debug: 3.2.7 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 @@ -8286,7 +8286,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): + /eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: @@ -8297,7 +8297,7 @@ packages: optional: true dependencies: '@rtsao/scc': 1.1.0 - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.1(eslint@8.57.1)(typescript@5.7.2) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.3 @@ -8306,7 +8306,7 @@ packages: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.0 is-glob: 4.0.3 @@ -8959,8 +8959,8 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true - /framer-motion@11.14.4(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-NQuzr9JbeJDMQmy0FFLhLzk9h1kAjVC1tGE/HY4ubF02B95EBm2lpA21LE3Od/OpXqXgp0zl5Hdqu25hliBRsA==} + /framer-motion@11.15.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-MLk8IvZntxOMg7lDBLw2qgTHHv664bYoYmnFTmE0Gm/FW67aOJk0WM3ctMcG+Xhcv+vh5uyyXwxvxhSeJzSe+w==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -9771,11 +9771,12 @@ packages: is-decimal: 2.0.1 dev: false - /is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + /is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 + call-bound: 1.0.3 get-intrinsic: 1.2.6 dev: true @@ -10606,7 +10607,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.10 + '@types/node': 22.10.2 chalk: 4.1.2 cjs-module-lexer: 1.4.1 collect-v8-coverage: 1.0.2 @@ -13275,14 +13276,14 @@ packages: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} dev: true - /react-markdown@9.0.1(@types/react@18.3.16)(react@18.3.1): + /react-markdown@9.0.1(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==} peerDependencies: '@types/react': '>=18' react: '>=18' dependencies: '@types/hast': 3.0.4 - '@types/react': 18.3.16 + '@types/react': 18.3.17 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.2 html-url-attributes: 3.0.1 @@ -13297,7 +13298,7 @@ packages: - supports-color dev: false - /react-remove-scroll-bar@2.3.8(@types/react@18.3.16)(react@18.3.1): + /react-remove-scroll-bar@2.3.8(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} peerDependencies: @@ -13307,13 +13308,13 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 - react-style-singleton: 2.2.3(@types/react@18.3.16)(react@18.3.1) + react-style-singleton: 2.2.3(@types/react@18.3.17)(react@18.3.1) tslib: 2.8.1 dev: false - /react-remove-scroll@2.6.0(@types/react@18.3.16)(react@18.3.1): + /react-remove-scroll@2.6.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==} engines: {node: '>=10'} peerDependencies: @@ -13323,13 +13324,13 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 - react-remove-scroll-bar: 2.3.8(@types/react@18.3.16)(react@18.3.1) - react-style-singleton: 2.2.3(@types/react@18.3.16)(react@18.3.1) + react-remove-scroll-bar: 2.3.8(@types/react@18.3.17)(react@18.3.1) + react-style-singleton: 2.2.3(@types/react@18.3.17)(react@18.3.1) tslib: 2.8.1 - use-callback-ref: 1.3.2(@types/react@18.3.16)(react@18.3.1) - use-sidecar: 1.1.3(@types/react@18.3.16)(react@18.3.1) + use-callback-ref: 1.3.2(@types/react@18.3.17)(react@18.3.1) + use-sidecar: 1.1.3(@types/react@18.3.17)(react@18.3.1) dev: false /react-resizable-panels@2.1.7(react-dom@18.3.1)(react@18.3.1): @@ -13342,7 +13343,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /react-style-singleton@2.2.3(@types/react@18.3.16)(react@18.3.1): + /react-style-singleton@2.2.3(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} peerDependencies: @@ -13352,7 +13353,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 get-nonce: 1.0.1 react: 18.3.1 tslib: 2.8.1 @@ -13372,7 +13373,7 @@ packages: refractor: 3.6.0 dev: false - /react-textarea-autosize@8.5.6(@types/react@18.3.16)(react@18.3.1): + /react-textarea-autosize@8.5.6(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-aT3ioKXMa8f6zHYGebhbdMD2L00tKeRX1zuVuDx9YQK/JLLRSaSxq3ugECEmUB9z2kvk6bFSIoRHLkkUv0RJiw==} engines: {node: '>=10'} peerDependencies: @@ -13380,8 +13381,8 @@ packages: dependencies: '@babel/runtime': 7.26.0 react: 18.3.1 - use-composed-ref: 1.4.0(@types/react@18.3.16)(react@18.3.1) - use-latest: 1.3.0(@types/react@18.3.16)(react@18.3.1) + use-composed-ref: 1.4.0(@types/react@18.3.17)(react@18.3.1) + use-latest: 1.3.0(@types/react@18.3.17)(react@18.3.1) transitivePeerDependencies: - '@types/react' dev: false @@ -13487,7 +13488,7 @@ packages: set-function-name: 2.0.2 dev: true - /rehackt@0.1.0(@types/react@18.3.16)(react@18.3.1): + /rehackt@0.1.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==} peerDependencies: '@types/react': '*' @@ -13498,7 +13499,7 @@ packages: react: optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false @@ -15411,7 +15412,7 @@ packages: resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} dev: true - /use-callback-ref@1.3.2(@types/react@18.3.16)(react@18.3.1): + /use-callback-ref@1.3.2(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} engines: {node: '>=10'} peerDependencies: @@ -15421,12 +15422,12 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 tslib: 2.8.1 dev: false - /use-composed-ref@1.4.0(@types/react@18.3.16)(react@18.3.1): + /use-composed-ref@1.4.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} peerDependencies: '@types/react': '*' @@ -15435,11 +15436,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /use-isomorphic-layout-effect@1.2.0(@types/react@18.3.16)(react@18.3.1): + /use-isomorphic-layout-effect@1.2.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} peerDependencies: '@types/react': '*' @@ -15448,11 +15449,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false - /use-latest@1.3.0(@types/react@18.3.16)(react@18.3.1): + /use-latest@1.3.0(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} peerDependencies: '@types/react': '*' @@ -15461,12 +15462,12 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 - use-isomorphic-layout-effect: 1.2.0(@types/react@18.3.16)(react@18.3.1) + use-isomorphic-layout-effect: 1.2.0(@types/react@18.3.17)(react@18.3.1) dev: false - /use-sidecar@1.1.3(@types/react@18.3.16)(react@18.3.1): + /use-sidecar@1.1.3(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} engines: {node: '>=10'} peerDependencies: @@ -15476,7 +15477,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 detect-node-es: 1.1.0 react: 18.3.1 tslib: 2.8.1 @@ -16004,7 +16005,7 @@ packages: /zod@3.24.1: resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} - /zustand@5.0.2(@types/react@18.3.16)(react@18.3.1): + /zustand@5.0.2(@types/react@18.3.17)(react@18.3.1): resolution: {integrity: sha512-8qNdnJVJlHlrKXi50LDqqUNmUbuBjoKLrYQBnoChIbVph7vni+sY+YpvdjXG9YLd/Bxr6scMcR+rm5H3aSqPaw==} engines: {node: '>=12.20.0'} peerDependencies: @@ -16022,7 +16023,7 @@ packages: use-sync-external-store: optional: true dependencies: - '@types/react': 18.3.16 + '@types/react': 18.3.17 react: 18.3.1 dev: false