From 7c007a69a62b44f49cb93da90def1c766916e504 Mon Sep 17 00:00:00 2001 From: thejoeymills <9663339+thejoeymills@user.noreply.gitee.com> Date: Tue, 3 Feb 2026 01:12:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E4=BC=98=E5=8C=96skills=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 12 +- backend/app/api/v1/async_tasks.py | 15 +- backend/app/api/v1/skills.py | 1 + backend/app/api/v1/skills_async.py | 104 +- backend/app/core/skills/skill_manager.py | 35 +- backend/app/core/task_manager.py | 49 + backend/app/core/task_persistence.py | 169 ++ backend/app/main.py | 3 +- backend/app/models/task.py | 1 + backend/data/tasks/tasks.json | 188 +++ .../modern-dialogue-writer/SKILL.md | 121 ++ .../user_skills/script-adapter/SKILL.md | 65 + frontend/package-lock.json | 1496 ++++++++--------- frontend/package.json | 28 +- frontend/src/components/SkillCreate.tsx | 263 ++- .../src/components/TaskProgressTracker.tsx | 18 +- frontend/src/pages/SkillManagement.tsx | 400 ++++- frontend/src/services/taskPollingService.ts | 237 +++ frontend/src/services/taskService.ts | 34 +- 审核系统修复报告.md | 123 -- 审核系统修复报告_补充.md | 157 -- 21 files changed, 2275 insertions(+), 1244 deletions(-) create mode 100644 backend/app/core/task_persistence.py create mode 100644 backend/data/tasks/tasks.json create mode 100644 backend/skills_storage/user_skills/modern-dialogue-writer/SKILL.md create mode 100644 backend/skills_storage/user_skills/script-adapter/SKILL.md create mode 100644 frontend/src/services/taskPollingService.ts delete mode 100644 审核系统修复报告.md delete mode 100644 审核系统修复报告_补充.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json index ede070f..03113b3 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -16,16 +16,8 @@ "Bash(tasklist:*)", "Bash(taskkill:*)", "Bash(where:*)", - "Bash(\"C:/ProgramData/Anaconda3/envs/creative_studio/python.exe\" -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload)", - "Bash(\"C:/ProgramData/Anaconda3/envs/creative_studio/python.exe\" -m pip install langchain langchain-core langgraph)", - "Bash(npm run dev:*)", - "Bash(\"C:\\\\ProgramData\\\\Anaconda3\\\\envs\\\\creative_studio\\\\python.exe\" --version)", - "Bash(\"C:\\\\ProgramData\\\\Anaconda3\\\\envs\\\\creative_studio\\\\python.exe\":*)", - "Bash(\"C:\\\\ProgramData\\\\Anaconda3\\\\envs\\\\creative_studio\\\\python.exe\" -c \"import langchain; print\\(''langchain version:'', langchain.__version__\\)\")", - "Bash(\"C:\\\\ProgramData\\\\Anaconda3\\\\envs\\\\creative_studio\\\\python.exe\" -c \"from langchain.agents import create_agent; print\\(''create_agent OK''\\)\")", - "Bash(\"C:\\\\ProgramData\\\\Anaconda3\\\\envs\\\\creative_studio\\\\python.exe\" -c \"from app.core.agent_runtime.agent import LangChainSkillsAgent; print\\(''Import OK''\\)\")", - "Bash(powershell -Command \"Get-Process | Where-Object {$_ProcessName -like ''*python*'' -or $_ProcessName -like ''*uvicorn*''}\")", - "Bash(\"C:\\\\ProgramData\\\\Anaconda3\\\\envs\\\\creative_studio\\\\python.exe\" -c \"import sys; sys.path.insert\\(0, r''d:\\\\platform\\\\creative_studio\\\\backend''\\); from app.api.v1.websocket import app; print\\(''WebSocket module import successful''\\)\")" + "Bash(cmd:*)", + "Bash(powershell \"Stop-Process -Id 365652 -Force; Stop-Process -Id 366104 -Force\")" ] } } diff --git a/backend/app/api/v1/async_tasks.py b/backend/app/api/v1/async_tasks.py index 2fed20b..8d52d13 100644 --- a/backend/app/api/v1/async_tasks.py +++ b/backend/app/api/v1/async_tasks.py @@ -42,6 +42,7 @@ async def create_task( type=task.type, status=task.status, progress=task.progress, + params=task.params, result=task.result, error=task.error, project_id=task.project_id, @@ -68,6 +69,7 @@ async def get_task( type=task.type, status=task.status, progress=task.progress, + params=task.params, result=task.result, error=task.error, project_id=task.project_id, @@ -102,12 +104,15 @@ async def list_tasks( if status: tasks = [t for t in tasks if t.status == status] - return [ + logger.info(f"list_tasks: task_type={task_type}, status={status}, found={len(tasks)} tasks") + + result = [ TaskResponse( id=t.id, type=t.type, status=t.status, progress=t.progress, + params=t.params, result=t.result, error=t.error, project_id=t.project_id, @@ -117,6 +122,12 @@ async def list_tasks( for t in tasks ] + # Log first task for debugging + if result: + logger.info(f"list_tasks: first task id={result[0].id}, status={result[0].status}, params keys={list(result[0].params.keys()) if result[0].params else 'none'}") + + return result + @router.post("/{task_id}/cancel", response_model=TaskResponse) async def cancel_task( @@ -137,6 +148,7 @@ async def cancel_task( type=task.type, status=task.status, progress=task.progress, + params=task.params, result=task.result, error=task.error, project_id=task.project_id, @@ -175,6 +187,7 @@ async def get_project_tasks( type=t.type, status=t.status, progress=t.progress, + params=t.params, result=t.result, error=t.error, project_id=t.project_id, diff --git a/backend/app/api/v1/skills.py b/backend/app/api/v1/skills.py index 2fd5419..b6970c4 100644 --- a/backend/app/api/v1/skills.py +++ b/backend/app/api/v1/skills.py @@ -9,6 +9,7 @@ Skill 管理 API 路由 5. Agent 工作流配置 6. 文档驱动的 Skill 生成(新增) """ +import re from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, status from typing import List, Optional, Dict, Any diff --git a/backend/app/api/v1/skills_async.py b/backend/app/api/v1/skills_async.py index f027cec..c898ed8 100644 --- a/backend/app/api/v1/skills_async.py +++ b/backend/app/api/v1/skills_async.py @@ -2,6 +2,12 @@ 异步 Skill 生成 API 将同步的 Skill 生成改为异步任务模式 + +特性: +1. 异步生成,后台执行 +2. 生成完成后自动保存到 skill-storage +3. 支持关闭弹窗后继续生成 +4. 任务持久化,重启后可恢复 """ from fastapi import APIRouter, HTTPException, Depends, BackgroundTasks from typing import Dict, Any, Optional, List @@ -9,11 +15,13 @@ from pydantic import BaseModel import asyncio import json import re +import uuid from app.core.llm.glm_client import get_glm_client from app.core.skills.skill_manager import get_skill_manager from app.core.task_manager import get_task_manager, TaskManager from app.models.task import TaskType, TaskStatus +from app.models.skill import SkillCreate from app.utils.logger import get_logger logger = get_logger(__name__) @@ -37,13 +45,21 @@ class GenerateSkillRequest(BaseModel): # 任务执行器 # ============================================================================ -async def execute_generate_skill( - task_manager: TaskManager, +async def execute_generate_skill_with_id( task_id: str, params: Dict[str, Any] ) -> Dict[str, Any]: - """执行 Skill 生成任务""" + """执行 Skill 生成任务(生成完成后自动保存) + + Args: + task_id: 任务ID + params: 任务参数,包含 description, category, tags, temperature 等 + + Returns: + 生成的 Skill 数据 + """ try: + task_manager = get_task_manager() glm_client = get_glm_client() skill_manager = get_skill_manager() @@ -110,14 +126,11 @@ async def execute_generate_skill( ) task_manager.update_task_progress( - task_id, 90, 100, - "正在处理结果..." + task_id, 75, 100, + "正在解析结果..." ) # 4. 解析响应 - import json - import re - response_text = response["choices"][0]["message"]["content"] json_match = re.search(r'\{[\s\S]*\}', response_text) @@ -133,9 +146,62 @@ async def execute_generate_skill( "explanation": "AI 生成的 Skill 内容" } + skill_content = result.get("skill_content", "") + suggested_id = result.get("suggested_id", "custom-skill") + suggested_name = result.get("suggested_name", "自定义 Skill") + category = result.get("category", params.get('category', '通用')) + suggested_tags = result.get("suggested_tags", []) + + task_manager.update_task_progress( + task_id, 90, 100, + "正在自动保存 Skill..." + ) + + # 5. 自动保存到 storage + # 确保 ID 唯一(如果已存在,添加随机后缀) + final_skill_id = suggested_id + counter = 1 + while True: + try: + # 检查 skill 是否已存在 + existing_skill = await skill_manager.load_skill(final_skill_id) + if existing_skill: + # ID 已存在,添加后缀 + final_skill_id = f"{suggested_id}-{counter}" + counter += 1 + else: + break + except: + # 加载失败说明不存在,可以使用这个 ID + break + + # 创建并保存 skill + skill_data = SkillCreate( + id=final_skill_id, + name=suggested_name, + content=skill_content, + category=category, + tags=suggested_tags + ) + + try: + saved_skill = await skill_manager.create_user_skill(skill_data) + logger.info(f"自动保存 Skill 成功: {final_skill_id}") + + # 更新结果中的 ID 为实际保存的 ID + result["suggested_id"] = final_skill_id + result["saved_skill_id"] = final_skill_id + result["auto_saved"] = True + except Exception as save_error: + logger.error(f"自动保存 Skill 失败: {str(save_error)}") + result["auto_saved"] = False + result["save_error"] = str(save_error) + # 即使保存失败,也返回生成的结果 + result["suggested_id"] = final_skill_id + task_manager.update_task_progress( task_id, 100, 100, - "生成完成!" + f"生成完成!Skill 已保存为: {final_skill_id}" ) return result @@ -145,6 +211,24 @@ async def execute_generate_skill( raise +async def execute_generate_skill(params: Dict[str, Any]) -> Dict[str, Any]: + """兼容旧版本的执行函数(通过查找当前任务获取task_id)""" + task_manager = get_task_manager() + + # 获取当前正在运行的任务 + running_tasks = task_manager.get_tasks_by_type(TaskType.GENERATE_SKILL) + current_task = None + for task in running_tasks: + if task.status == TaskStatus.RUNNING: + current_task = task + break + + if not current_task: + raise Exception("找不到正在运行的任务") + + return await execute_generate_skill_with_id(current_task.id, params) + + # ============================================================================ # 异步任务创建端点 # ============================================================================ @@ -170,7 +254,7 @@ async def generate_skill_async( async def run_task(): await task_manager.execute_task_async( task.id, - lambda p: execute_generate_skill(task_manager, task.id, p) + execute_generate_skill ) asyncio.create_task(run_task()) diff --git a/backend/app/core/skills/skill_manager.py b/backend/app/core/skills/skill_manager.py index 48aa43a..afc3bb9 100644 --- a/backend/app/core/skills/skill_manager.py +++ b/backend/app/core/skills/skill_manager.py @@ -17,6 +17,7 @@ import json import sys from datetime import datetime import yaml +import asyncio from app.models.skill import Skill, SkillCreate, SkillUpdate from app.config import settings @@ -157,6 +158,18 @@ class SkillManager: logger.info(f"Skill 管理器初始化完成,目录: {self.skills_dir}") + # 技能列表缓存(用于快速返回列表,不需要每次都扫描目录) + self._skills_list_cache: Optional[List[Skill]] = None + self._cache_dirty = True # 标记缓存需要更新 + + async def warmup_cache(self): + """预热缓存 - 在应用启动时调用,预加载所有 skills""" + logger.info("开始预热 Skill 缓存...") + skills = await self.list_skills() + self._skills_list_cache = skills + self._cache_dirty = False + logger.info(f"Skill 缓存预热完成,共加载 {len(skills)} 个 skills") + async def load_skill(self, skill_id: str) -> Optional[Skill]: """ 加载 Skill @@ -179,7 +192,7 @@ class SkillManager: return None try: - # 解析 SKILL.md + # 解析 SKILL.md(异步读取文件) skill = await self._parse_skill_file(skill_path, skill_id) # 缓存 @@ -220,7 +233,8 @@ class SkillManager: Returns: Skill 对象 """ - content = skill_path.read_text(encoding='utf-8') + # 使用 asyncio.to_thread 在单独的线程中读取文件,避免阻塞事件循环 + content = await asyncio.to_thread(skill_path.read_text, encoding='utf-8') # 确定类型 skill_type = "builtin" if "builtin_skills" in str(skill_path) else "user" @@ -235,7 +249,7 @@ class SkillManager: has_scripts = (skill_path.parent / "scripts").exists() tools = [] if has_scripts: - tools = self._load_tools(skill_path.parent / "scripts") + tools = await asyncio.to_thread(self._load_tools, skill_path.parent / "scripts") return Skill( id=skill_id, @@ -375,6 +389,10 @@ class SkillManager: Returns: Skill 列表 """ + # 如果不需要筛选且有缓存,直接返回缓存 + if not skill_type and not category and self._skills_list_cache is not None: + return self._skills_list_cache + skills = [] # 扫描内置 Skills @@ -393,6 +411,10 @@ class SkillManager: if skill and (category is None or skill.category == category): skills.append(skill) + # 如果没有筛选条件,更新缓存 + if not skill_type and not category: + self._skills_list_cache = skills + return skills async def create_user_skill(self, skill_data: SkillCreate) -> Skill: @@ -413,6 +435,9 @@ class SkillManager: skill_file = skill_dir / "SKILL.md" skill_file.write_text(skill_data.content, encoding='utf-8') + # 清除列表缓存 + self._skills_list_cache = None + logger.info(f"创建用户 Skill: {skill_data.id}") # 加载并返回 @@ -455,6 +480,9 @@ class SkillManager: # 写入更新后的内容 skill_path.write_text(content, encoding='utf-8') + # 清除缓存 + self._skills_list_cache = None + # 重新加载 return await self.reload_skill(skill_id) @@ -484,6 +512,7 @@ class SkillManager: # 清除缓存 if skill_id in self._cache: del self._cache[skill_id] + self._skills_list_cache = None logger.info(f"删除用户 Skill: {skill_id}") return True diff --git a/backend/app/core/task_manager.py b/backend/app/core/task_manager.py index 95ec034..66a732a 100644 --- a/backend/app/core/task_manager.py +++ b/backend/app/core/task_manager.py @@ -11,6 +11,7 @@ from collections import defaultdict from app.models.task import AsyncTask, TaskStatus, TaskType, TaskProgress from app.utils.logger import get_logger +from app.core.task_persistence import get_task_persistence logger = get_logger(__name__) @@ -33,6 +34,11 @@ class TaskManager: self._project_tasks: Dict[str, List[str]] = defaultdict(list) # 按类型索引的任务 self._type_tasks: Dict[TaskType, List[str]] = defaultdict(list) + # 持久化存储 + self._persistence = get_task_persistence() + + # 启动时恢复持久化的任务 + self._restore_tasks() def create_task( self, @@ -68,6 +74,9 @@ class TaskManager: self._type_tasks[task_type].append(task_id) + # 保存到持久化存储 + self._persistence.save_task(task) + logger.info(f"创建任务: {task_id} ({task_type.value})") return task @@ -162,6 +171,9 @@ class TaskManager: elif status in [TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED]: task.completed_at = datetime.now() + # 更新持久化存储 + self._persistence.update_task_status(task_id, status, result, error) + logger.info(f"任务状态更新: {task_id} - {old_status.value} -> {status.value}") return True @@ -188,6 +200,9 @@ class TaskManager: del self._tasks[task_id] + # 从持久化存储中删除 + self._persistence.delete_task(task_id) + logger.info(f"删除任务: {task_id}") return True @@ -245,6 +260,40 @@ class TaskManager: """ return asyncio.create_task(self.execute_task_async(task_id, executor)) + def _restore_tasks(self) -> None: + """从持久化存储恢复任务""" + try: + saved_tasks = self._persistence.get_all_tasks() + restored_count = 0 + + for task_id, task_data in saved_tasks.items(): + # 跳过已完成、失败或取消的任务(太久远的不需要恢复) + if task_data.get('status') in ['completed', 'failed', 'cancelled']: + continue + + # 恢复任务到内存 + try: + task = AsyncTask(**task_data) + self._tasks[task_id] = task + + # 恢复索引 + if task.project_id: + self._project_tasks[task.project_id].append(task_id) + self._type_tasks[task.type].append(task_id) + + restored_count += 1 + except Exception as e: + logger.warning(f"恢复任务失败: {task_id} - {e}") + + if restored_count > 0: + logger.info(f"从持久化存储恢复了 {restored_count} 个任务") + + # 清理旧任务(超过24小时的已完成任务) + self._persistence.cleanup_old_tasks(max_age_hours=24) + + except Exception as e: + logger.error(f"恢复任务失败: {e}") + # 全局单例 _task_manager: Optional[TaskManager] = None diff --git a/backend/app/core/task_persistence.py b/backend/app/core/task_persistence.py new file mode 100644 index 0000000..1c57127 --- /dev/null +++ b/backend/app/core/task_persistence.py @@ -0,0 +1,169 @@ +""" +任务持久化存储 + +使用文件系统持久化任务状态,支持: +1. 服务重启后恢复任务 +2. 前端刷新后可继续查看任务 +""" +import json +import os +from datetime import datetime +from typing import Dict, List, Optional +from pathlib import Path + +from app.models.task import AsyncTask, TaskStatus +from app.utils.logger import get_logger + +logger = get_logger(__name__) + + +class TaskPersistence: + """任务持久化管理器""" + + def __init__(self, storage_dir: str = "data/tasks"): + self.storage_dir = Path(storage_dir) + self.storage_dir.mkdir(parents=True, exist_ok=True) + self.tasks_file = self.storage_dir / "tasks.json" + + def save_task(self, task: AsyncTask) -> bool: + """保存单个任务""" + try: + tasks = self._load_all_tasks() + tasks[task.id] = task.model_dump(mode='json') + self._save_all_tasks(tasks) + return True + except Exception as e: + logger.error(f"保存任务失败: {task.id} - {e}") + return False + + def get_task(self, task_id: str) -> Optional[Dict]: + """获取任务""" + try: + tasks = self._load_all_tasks() + return tasks.get(task_id) + except Exception as e: + logger.error(f"获取任务失败: {task_id} - {e}") + return None + + def get_all_tasks(self) -> Dict[str, Dict]: + """获取所有任务""" + try: + return self._load_all_tasks() + except Exception as e: + logger.error(f"获取所有任务失败: {e}") + return {} + + def delete_task(self, task_id: str) -> bool: + """删除任务""" + try: + tasks = self._load_all_tasks() + if task_id in tasks: + del tasks[task_id] + self._save_all_tasks(tasks) + return True + except Exception as e: + logger.error(f"删除任务失败: {task_id} - {e}") + return False + + def update_task_status( + self, + task_id: str, + status: TaskStatus, + result: Optional[Dict] = None, + error: Optional[str] = None + ) -> bool: + """更新任务状态""" + try: + tasks = self._load_all_tasks() + if task_id not in tasks: + return False + + task_data = tasks[task_id] + task_data['status'] = status.value + task_data['updated_at'] = datetime.now().isoformat() + + if result is not None: + task_data['result'] = result + + if error is not None: + task_data['error'] = error + + self._save_all_tasks(tasks) + return True + except Exception as e: + logger.error(f"更新任务状态失败: {task_id} - {e}") + return False + + def cleanup_old_tasks(self, max_age_hours: int = 24) -> int: + """清理旧任务(已完成/失败/取消超过指定时间的任务)""" + try: + tasks = self._load_all_tasks() + now = datetime.now() + to_delete = [] + + for task_id, task_data in tasks.items(): + # 跳过运行中的任务 + if task_data.get('status') in ['running', 'pending']: + continue + + # 检查任务年龄 + updated_at = task_data.get('updated_at') + if updated_at: + try: + update_time = datetime.fromisoformat(updated_at) + age_hours = (now - update_time).total_seconds() / 3600 + if age_hours > max_age_hours: + to_delete.append(task_id) + except: + pass + + # 删除旧任务 + for task_id in to_delete: + del tasks[task_id] + + if to_delete: + self._save_all_tasks(tasks) + logger.info(f"清理了 {len(to_delete)} 个旧任务") + + return len(to_delete) + except Exception as e: + logger.error(f"清理旧任务失败: {e}") + return 0 + + def _load_all_tasks(self) -> Dict[str, Dict]: + """加载所有任务""" + if not self.tasks_file.exists(): + return {} + + try: + with open(self.tasks_file, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + logger.error(f"加载任务文件失败: {e}") + return {} + + def _save_all_tasks(self, tasks: Dict[str, Dict]) -> None: + """保存所有任务""" + try: + # 先写入临时文件,然后重命名,避免写入失败导致数据丢失 + temp_file = self.tasks_file.with_suffix('.tmp') + with open(temp_file, 'w', encoding='utf-8') as f: + json.dump(tasks, f, ensure_ascii=False, indent=2) + + # 重命名 + temp_file.replace(self.tasks_file) + except Exception as e: + logger.error(f"保存任务文件失败: {e}") + raise + + +# 全局单例 +_persistence: Optional[TaskPersistence] = None + + +def get_task_persistence() -> TaskPersistence: + """获取任务持久化单例""" + global _persistence + if _persistence is None: + _persistence = TaskPersistence() + return _persistence diff --git a/backend/app/main.py b/backend/app/main.py index 0f0c370..9839d31 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -23,7 +23,8 @@ async def lifespan(app: FastAPI): # 初始化 Skill 管理器 from app.core.skills.skill_manager import get_skill_manager skill_manager = get_skill_manager() - logger.info(f"✅ Skill 管理器初始化完成,已加载 {len(await skill_manager.list_skills())} 个 Skills") + # 预热 Skill 缓存(异步加载所有 skills,避免首次请求阻塞) + await skill_manager.warmup_cache() # 注册 Builtin Skills 的工具(Agent-Skill 生命周期:注册阶段) await skill_manager.register_builtin_tools() diff --git a/backend/app/models/task.py b/backend/app/models/task.py index cd56bec..414d24a 100644 --- a/backend/app/models/task.py +++ b/backend/app/models/task.py @@ -75,6 +75,7 @@ class TaskResponse(BaseModel): type: TaskType status: TaskStatus progress: TaskProgress + params: Dict[str, Any] = Field(default_factory=dict) result: Optional[Dict[str, Any]] = None error: Optional[str] = None project_id: Optional[str] = None diff --git a/backend/data/tasks/tasks.json b/backend/data/tasks/tasks.json new file mode 100644 index 0000000..6a04806 --- /dev/null +++ b/backend/data/tasks/tasks.json @@ -0,0 +1,188 @@ +{ + "bba4efe7-127f-4a90-bee3-0dbac02e0fbb": { + "id": "bba4efe7-127f-4a90-bee3-0dbac02e0fbb", + "type": "generate_skill", + "status": "completed", + "progress": { + "current": 0, + "total": 100, + "message": "", + "stage": null + }, + "params": { + "description": "生成一个剧本改编skill", + "category": null, + "tags": null, + "temperature": 0.7 + }, + "result": { + "suggested_id": "screenplay-adaptation", + "suggested_name": "剧本改编专家", + "skill_content": "---\nname: screenplay-adaptation\ndescription: 将小说、故事或叙事文本转换为专业剧本格式。适用于将文字描述转化为场景标题、动作描述和对白。专注于将内心独白外化、压缩时间线、视觉化叙事以及保持标准剧本格式。\n---\n\n# 剧本改编流程\n\n## 核心工作流\n\n遵循以下步骤将文本改编为剧本:\n\n1. **分析源材料**\n * 识别核心冲突、关键情节转折和主要角色。\n * 标记必须保留的视觉化场景。\n\n2. **场景拆解**\n * 将叙事文本分解为独立的场景。\n * 确定每个场景的地点(内/外)和时间(日/夜)。\n * 列出每个场景中的出场角色。\n\n3. **起草剧本**\n * **场景标题 (Slugline)**:使用标准格式(例如:`内景. 咖啡馆 - 日`)。\n * **动作描述 (Action)**:只描述观众能看到和听到的东西。避免使用“他想”、“她觉得”。\n * **对白 (Dialogue)**:将叙述性解释转化为角色之间的对话。使用潜台词。\n\n4. **润色与精简**\n * 删除无法拍摄的内容。\n * 检查对白是否自然。\n * 确保格式统一。\n\n## 改编关键原则\n\n### 展示而非讲述\n* **错误**:约翰感到很生气,因为他输了比赛。\n* **正确**:约翰狠狠地摔下球拍,拳头砸在墙上。\n\n### 内心独白外化\n* 将角色的内心想法转化为视觉动作或对白。\n* 如果必须表达想法,考虑使用画外音 (V.O.),但尽量优先使用视觉表达。\n\n### 压缩时间与空间\n* 合并发生在同一地点但不同时间的场景。\n* 删除对情节推进无用的过渡场景。\n\n## 标准剧本格式参考\n\n使用以下标准结构:\n\n```text\n场景标题 (Slugline)\n内景. 地点 - 时间\n\n动作描述 (Action)\n描述场景中发生的视觉和听觉事件。\n\n角色名 (Character)\n居中对齐的角色名称。\n\n对白 (Dialogue)\n角色说的话。\n\n(括号说明)\n语气或动作的简短提示。\n```\n\n## 注意事项\n\n* **格式一致性**:确保全篇剧本的缩进和标点符号一致。\n* **一页一分钟**:通常剧本的一页对应屏幕时间的一分钟。注意控制场景长度。", + "category": "编剧", + "suggested_tags": [ + "剧本", + "改编", + "编剧", + "格式化" + ], + "explanation": "这个 Skill 专注于将叙事文本(如小说)转换为剧本格式。它提供了结构化的工作流(分析、拆解、起草、润色)和具体的改编原则(如“展示而非讲述”),帮助 Claude 生成符合行业标准的剧本。" + }, + "error": null, + "project_id": null, + "created_at": "2026-02-03T00:13:07.204960", + "started_at": null, + "completed_at": null, + "updated_at": "2026-02-03T00:13:43.809136" + }, + "5d86feb1-31c9-4760-952e-1960234a813c": { + "id": "5d86feb1-31c9-4760-952e-1960234a813c", + "type": "generate_skill", + "status": "completed", + "progress": { + "current": 0, + "total": 100, + "message": "", + "stage": null + }, + "params": { + "description": "创建一个剧本改编skill", + "category": null, + "tags": null, + "temperature": 0.7 + }, + "result": { + "suggested_id": "script-adapter", + "suggested_name": "剧本改编专家", + "skill_content": "---\nname: script-adapter\ndescription: 将小说、故事或其他文学作品改编为标准影视或舞台剧本。用于将文本转化为剧本格式、优化对白、构建分场大纲,以及处理“展示而非讲述”的改编需求。当用户要求“把小说改成剧本”、“写个剧本”、“格式化剧本”或进行剧本创作时使用。\n---\n\n# 剧本改编指南\n\n本 Skill 提供将叙事文本转化为标准剧本格式的指导原则和工作流。\n\n## 核心工作流\n\n1. **素材分析**:提取核心冲突、人物动机、关键情节点和主题。\n2. **结构提炼**:将故事拆解为场景列表,确定叙事节奏(如三幕式结构)。\n3. **场景转化**:将描述性文字转化为动作描述和对白,遵循“展示而非讲述”原则。\n4. **格式规范**:应用标准剧本格式(场景标题、动作、角色名、对白、括号备注)。\n\n## 标准剧本格式\n\n严格遵循以下格式规范:\n\n- **场景标题**:[内/外景] 地点 - [日/夜]\n - 示例:`内景. 咖啡馆 - 日`\n- **动作描述**:现在时态,只描述可见和可听的内容。\n - 错误:`约翰感到很悲伤。`\n - 正确:`约翰低下头,双手紧握咖啡杯。`\n- **角色名**:居中,位于对白上方。\n- **对白**:角色口中说的内容。\n- **括号备注**:位于角色名下方,指示语气或微小动作(慎用)。\n\n## 改编关键原则\n\n### 展示而非讲述\n- **内心独白外化**:将角色的心理活动转化为具体的动作、表情或对白。\n- **视觉化叙事**:优先使用视觉元素传达信息,减少依赖旁白。\n\n### 节奏与压缩\n- **删减冗余**:去除不推动剧情发展的支线情节。\n- **合并场景**:将发生在不同时间但功能相似的场景合并,以保持紧凑感。\n\n### 对白优化\n- **潜台词**:让角色说出的话与其真实意图之间存在差距,增加戏剧张力。\n- **声音区分**:确保每个角色的说话方式、词汇选择符合其性格和背景。\n\n## 参考资源\n\n- **结构模板**:参见 `references/structure.md` 了解经典叙事结构(如救猫咪、英雄之旅)。\n- **格式示例**:参见 `references/formatting-examples.md` 查看具体格式范例。\n", + "category": "编剧", + "suggested_tags": [ + "剧本", + "改编", + "影视", + "写作", + "格式化" + ], + "explanation": "该 Skill 专注于将小说、故事等叙事文本转化为标准的影视/舞台剧本。它定义了清晰的四步工作流(分析、提炼、转化、格式化),并强调了剧本改编的核心原则——如“展示而非讲述”和“视觉化叙事”。同时,它提供了严格的格式规范指导,确保输出符合行业标准。通过引用 `references/` 目录下的结构模板和格式示例,该 Skill 实现了核心指令与详细参考资料的分离,既保证了指令的简洁性,又支持了深度创作需求。" + }, + "error": null, + "project_id": null, + "created_at": "2026-02-03T00:19:06.464946", + "started_at": null, + "completed_at": null, + "updated_at": "2026-02-03T00:20:00.347558" + }, + "6f721ad2-370f-4550-b5b7-c2c300ea262b": { + "id": "6f721ad2-370f-4550-b5b7-c2c300ea262b", + "type": "generate_skill", + "status": "completed", + "progress": { + "current": 0, + "total": 100, + "message": "", + "stage": null + }, + "params": { + "description": "创建一个剧本改编skill", + "category": null, + "tags": null, + "temperature": 0.7 + }, + "result": { + "suggested_id": "script-adapter", + "suggested_name": "剧本改编专家", + "skill_content": "---\nname: script-adapter\ndescription: 专注于将小说、故事、真实事件或原始素材改编为标准剧本格式。适用于将叙事文本转化为视觉脚本、将故事结构拆解为场景、提炼对白以符合影视/舞台要求,以及进行跨媒介的文本改编工作。\n---\n\n# 剧本改编专家\n\n本 Skill 提供将叙事文本转换为标准剧本格式的流程、原则和规范。\n\n## 核心工作流程\n\n遵循以下步骤进行改编,确保从叙事到视觉的平滑过渡:\n\n1. **素材分析**\n * 识别核心冲突、主要人物弧光和关键情节点。\n * 区分必须保留的情节和可以删减的支线。\n\n2. **结构拆解**\n * 将故事分解为场景列表。\n * 确定每个场景的叙事目标(推进情节、揭示人物、营造氛围)。\n\n3. **场景写作**\n * 将小说中的描写转化为动作描述。\n * 将内心独白转化为视觉动作或对白。\n\n4. **格式规范**\n * 应用标准剧本格式(见下文“格式标准”)。\n\n## 改编核心原则\n\n### 视觉化表达\n* **展示而非讲述**:不要写“他感到很悲伤”,而要写“他盯着空荡荡的椅子,久久没有说话”。\n* **外化内心活动**:将心理描写转化为具体的动作、表情或环境反应。\n\n### 压缩与提炼\n* **场景合并**:将发生在同一地点、时间的多个段落合并为一个场景。\n* **对白精炼**:删除日常寒暄,确保每句对白都有潜台词或推动剧情。\n* **删除说明性文字**:避免让角色说出观众已经知道的信息。\n\n### 冲突外化\n* 确保每个场景都有明确的冲突或转折。\n* 通过角色之间的互动来展现矛盾,而不是通过旁白。\n\n## 标准剧本格式\n\n严格遵循以下格式规范:\n\n### 1. 场景标题\n* **格式**:[内/外] 地点 - [日/夜]\n* **示例**:`内. 咖啡馆 - 日`\n* **规则**:每个新场景以此开始,首次出现的地点需大写。\n\n### 2. 动作描述\n* **格式**:现在时态,左对齐。\n* **内容**:描述场景中发生的事情、角色的动作和环境细节。\n* **规则**:只描述观众能看到和听到的东西。\n\n### 3. 角色名\n* **格式**:全部大写,居中(或距离左边距一定距离)。\n* **示例**:`李明`\n* **规则**:角色首次出现时需在动作描述中标注年龄和特征。\n\n### 4. 对白\n* **格式**:位于角色名下方,居中。\n* **规则**:口语化,符合角色性格。\n\n### 5. 副语言说明\n* **格式**:括号内,位于角色名和对白之间。\n* **示例**:`(低声)`、`(愤怒地)`\n* **规则**:仅在语气无法通过对白本身传达时使用,避免滥用。\n\n## 输出示例\n\n```markdown\n内. 旧公寓 - 夜\n\n窗外霓虹灯闪烁。李明(30岁,面容憔悴)坐在沙发上,手里紧紧攥着一张照片。\n\n门锁转动。张华推门进来,手里提着便利店的袋子。\n\n张华\n还没睡?\n\n李明没有抬头,只是把照片反扣在桌面上。\n\n李明\n我们需要谈谈。\n```\n\n## 常见改编陷阱\n\n* **过度依赖旁白**:尽量用画面讲故事,旁白是最后手段。\n* **保留过多次要角色**:合并功能相似的角色,简化人物关系。\n* **忽视节奏**:通过场景的长短和交替来控制叙事节奏(如动作戏场景短,情感戏场景长)。\n", + "category": "编剧", + "suggested_tags": [ + "剧本", + "改编", + "影视", + "写作", + "格式规范" + ], + "explanation": "该 Skill 专注于将小说、故事等叙事文本改编为标准影视剧本。它提供了从素材分析到格式化输出的完整工作流程,强调了“视觉化表达”、“压缩提炼”和“冲突外化”等改编核心原则,并定义了标准的剧本格式规范(场景标题、动作、角色、对白),帮助 Claude 高效地完成跨媒介的文本转换工作。" + }, + "error": null, + "project_id": null, + "created_at": "2026-02-03T00:31:44.308553", + "started_at": null, + "completed_at": null, + "updated_at": "2026-02-03T00:32:04.210026" + }, + "96d9a716-ceff-43b9-952e-57d7b08b28bb": { + "id": "96d9a716-ceff-43b9-952e-57d7b08b28bb", + "type": "generate_skill", + "status": "completed", + "progress": { + "current": 0, + "total": 100, + "message": "", + "stage": null + }, + "params": { + "description": "创建一个剧本改编skill", + "category": null, + "tags": null, + "temperature": 0.7 + }, + "result": { + "suggested_id": "script-adaptation", + "suggested_name": "剧本改编", + "skill_content": "---\nname: script-adaptation\ndescription: 将小说、故事或其他文本内容改编为标准剧本格式。适用于将文学作品转化为影视剧本、舞台剧剧本等场景,包括:提取对话、构建场景、编写动作描述、处理转场、保持原作核心情节和人物性格。当用户需要将文本改编为剧本时使用此技能。\n---\n\n# 剧本改编\n\n## 核心原则\n\n### 视觉化叙事\n- 将文字描述转化为可拍摄的动作和画面\n- 避免内心独白,通过行为和对话展现角色状态\n- 每个场景都应有明确的视觉目标\n\n### 保持原作精髓\n- 保留核心情节和关键转折点\n- 维持人物性格和关系动态\n- 提取并优化原作中的精彩对话\n\n## 剧本格式标准\n\n### 场景标题(Slugline)\n```\n内景. 咖啡馆 - 日\nEXT. PARK - NIGHT\n```\n- 格式:[内/外景]. [地点] - [时间]\n- 每个新场景开始时使用\n\n### 动作描述(Action)\n- 使用现在时\n- 简洁有力,突出关键动作\n- 避免过度描述,只保留拍摄必要的信息\n\n### 对话(Dialogue)\n```\n角色名\n(括号内的动作/语气指示)\n对话内容\n```\n- 角色名居中\n- 括号指示可选,用于补充表演提示\n- 对话自然口语化\n\n### 转场(Transition)\n```\n切至:\n淡入:\n黑屏:\n```\n- 位于场景结尾\n- 简洁明确\n\n## 改编流程\n\n### 1. 分析原作\n- 识别核心冲突和主题\n- 列出主要人物及其关系\n- 标记关键场景和情节节点\n\n### 2. 场景拆分\n- 将原作按场景重新组织\n- 确定每个场景的地点和时间\n- 删除或合并不必要的场景\n\n### 3. 对话提取与改编\n- 提取原作中的直接对话\n- 将叙述性内容转化为对话\n- 精简冗长对话,增强戏剧张力\n\n### 4. 动作描述编写\n- 将环境描写转化为视觉动作\n- 通过动作展现人物心理\n- 保持节奏和张力\n\n### 5. 格式规范化\n- 应用标准剧本格式\n- 检查转场逻辑\n- 确保页码和场景连续性\n\n## 常见挑战处理\n\n### 内心戏外化\n- 通过表情、动作、环境反应展现\n- 使用画外音(V.O.)或闪回(FLASHBACK)\n- 创造象征性视觉元素\n\n### 时间压缩\n- 合并相似场景\n- 使用蒙太奇(MONTAGE)表现时间流逝\n- 删除次要情节线\n\n### 人物精简\n- 合并功能相似的角色\n- 删除对主线无推动作用的角色\n- 保留核心人物弧光\n\n## 质量检查清单\n\n- [ ] 所有场景都有正确的场景标题\n- [ ] 动作描述使用现在时\n- [ ] 对话符合角色性格\n- [ ] 核心情节完整保留\n- [ ] 转场逻辑清晰\n- [ ] 格式统一规范\n\n## 参考资源\n\n- **详细格式示例**:见 [references/format-examples.md](references/format-examples.md)\n- **经典剧本分析**:见 [references/classic-scripts.md](references/classic-scripts.md)\n- **改编案例研究**:见 [references/adaptation-cases.md](references/adaptation-cases.md)\n", + "category": "编剧", + "suggested_tags": [ + "剧本", + "改编", + "影视", + "编剧", + "格式" + ], + "explanation": "这个 Skill 提供了将文本内容改编为剧本的完整指导。包含了剧本格式标准(场景标题、动作描述、对话、转场)、改编流程(分析原作、场景拆分、对话提取、动作编写、格式规范化)、常见挑战处理(内心戏外化、时间压缩、人物精简)以及质量检查清单。采用了渐进式披露设计,核心流程在 SKILL.md 中,详细示例和案例研究放在 references/ 目录下,保持主文件简洁高效。" + }, + "error": null, + "project_id": null, + "created_at": "2026-02-03T00:37:34.960133", + "started_at": null, + "completed_at": null, + "updated_at": "2026-02-03T00:37:57.575299" + }, + "de53d476-455b-4324-bf04-1cd3860e3ede": { + "id": "de53d476-455b-4324-bf04-1cd3860e3ede", + "type": "generate_skill", + "status": "completed", + "progress": { + "current": 0, + "total": 100, + "message": "", + "stage": null + }, + "params": { + "description": "创建一个剧本改编skill", + "category": null, + "tags": null, + "temperature": 0.7 + }, + "result": { + "suggested_id": "script-adapter", + "suggested_name": "剧本改编专家", + "skill_content": "---\nname: script-adapter\ndescription: Adapt novels, stories, or concepts into professional screenplay format (film/theater/TV). Use when user needs to transform narrative text into scripts, including scene breakdown, dialogue conversion, visual storytelling, and standard industry formatting.\n---\n\n# Script Adapter\n\nTransform source material into professional screenplays using industry-standard formatting and visual storytelling techniques.\n\n## Core Principles\n\n- **Show, Don't Tell**: Convert internal monologues and descriptions into visible actions and subtextual dialogue.\n- **Visual Narrative**: Prioritize actions that can be seen and heard over abstract descriptions.\n- **Economy of Words**: Keep action lines concise and dialogue sharp.\n\n## Adaptation Workflow\n\n### 1. Analyze Source Material\nIdentify and extract:\n- Core conflict and theme\n- Protagonist's arc and motivation\n- Key plot points (inciting incident, climax, resolution)\n- Essential characters (combine minor characters if necessary)\n\n### 2. Structure the Narrative\nMap the source material to a standard structure:\n- **Three-Act Structure**: Setup, Confrontation, Resolution\n- **Scene List**: Break down the story into specific locations and timeframes\n- **Pacing**: Ensure the flow works for visual media (faster than prose)\n\n### 3. Draft the Scene\nFor each scene:\n1. **Slugline**: INT./EXT. LOCATION - DAY/NIGHT\n2. **Action**: Describe what happens visually (present tense).\n3. **Character Name**: Centered, uppercase.\n4. **Dialogue**: What the character says.\n5. **Parenthetical**: How the character says it (use sparingly).\n\n### 4. Refine and Format\n- Check standard margins and spacing.\n- Ensure all scenes drive the plot or reveal character.\n- Remove exposition-heavy dialogue; replace with action.\n\n## Standard Format Guide\n\n```text\nSLUGLINE: INT. LOCATION - DAY\n\nAction lines describe what the audience sees. Be specific and visual.\n\nCHARACTER NAME\n(parenthetical direction)\nDialogue goes here.\n\nEXT. STREET - NIGHT\n\nMore action.\n```\n\n## Key Adaptation Techniques\n\n- **Internal to External**: Convert \"He felt sad\" to \"He stared at the floor, shoulders slumped.\"\n- **Compression**: Merge multiple conversations from the book into one impactful scene.\n- **Subtext**: Characters should rarely say exactly what they mean. Use silence and action to convey true feelings.\n- **Enter Late, Leave Early**: Start scenes at the last possible moment and end them as soon as the main point is made.", + "category": "编剧", + "suggested_tags": [ + "剧本", + "改编", + "编剧", + "电影", + "格式化" + ], + "explanation": "该 Skill 专注于将小说、故事或概念转化为专业的剧本格式。它提供了从素材分析、结构搭建到场景起草的完整工作流,强调了“展示不要讲述”的核心原则,并包含了标准的剧本格式指南。适用于需要将文本转化为视觉叙事的场景。", + "saved_skill_id": "script-adapter", + "auto_saved": true + }, + "error": null, + "project_id": null, + "created_at": "2026-02-03T00:50:46.553278", + "started_at": null, + "completed_at": null, + "updated_at": "2026-02-03T00:51:21.223438" + } +} \ No newline at end of file diff --git a/backend/skills_storage/user_skills/modern-dialogue-writer/SKILL.md b/backend/skills_storage/user_skills/modern-dialogue-writer/SKILL.md new file mode 100644 index 0000000..f0dcbcf --- /dev/null +++ b/backend/skills_storage/user_skills/modern-dialogue-writer/SKILL.md @@ -0,0 +1,121 @@ +--- +name: modern-dialogue-writer +description: 创建自然、流畅的现代风格对话内容,适用于小说、剧本、游戏等场景。支持当代语言习惯、网络用语、俚语等现代表达方式。当用户需要:编写人物对话、润色对话使其更自然、创作现代场景对话、调整对话语气和风格、处理多角色互动对话时使用此Skill。 +--- + +# 现代对话创作 + +## 核心原则 + +### 自然流畅 +- 使用口语化表达,避免过于书面化 +- 加入语气词(嘛、呢、呗、呗、啊)增强真实感 +- 适当使用省略号、破折号表现说话节奏 +- 允许不完整句子、重复、打断等真实对话特征 + +### 现代语言特征 +- 融入网络用语和流行梗(适度) +- 使用缩略语和简化表达(如"啥"代替"什么") +- 体现时代感的词汇和表达方式 +- 根据角色年龄、身份调整语言风格 + +### 对话节奏 +- 长短句交替,避免单调 +- 控制信息密度,不要一次性输出过多 +- 使用沉默、动作描写调节节奏 +- 根据紧张程度调整对话速度 + +## 对话模式 + +### 日常对话 +- 轻松随意,多用省略和简化 +- 关注生活细节和琐事 +- 话题跳跃性强 +- 示例: + ``` + "哎,你看了没?" + "啥?" + "就那个热搜啊,炸了。" + "哦,那个啊,早刷到了。" + ``` + +### 职场对话 +- 相对正式但不过于生硬 +- 使用专业术语但要自然 +- 体现层级关系和职场文化 +- 示例: + ``` + "李总,方案我发你邮箱了。" + "收到,我看看。" + "有问题随时滴滴我。" + ``` + +### 网络聊天 +- 使用表情符号和颜文字 +- 大量使用网络缩写和梗 +- 语气夸张,情绪化明显 +- 示例: + ``` + "哈哈哈哈笑死我了" + "真的吗????" + "绝了家人们" + ``` + +## 角色声音塑造 + +### 区分角色 +- 每个角色有独特的说话方式 +- 常用词汇、句式结构、语气词 +- 语言习惯(如口头禅、语速快慢) + +### 年龄差异 +- 青年:网络用语多,表达直接 +- 中年:相对稳重,但不过时 +- 老年:传统表达,可能跟不上网络梗 + +### 地域特色 +- 适度融入方言词汇 +- 注意不要过度使用影响理解 +- 体现文化背景 + +## 润色技巧 + +### 去除生硬感 +- 删除过于正式的词汇 +- 增加语气词和口语化表达 +- 打破完整句子结构 + +### 增强画面感 +- 加入动作描写 +- 描写表情和神态 +- 通过对话展现环境 + +### 潜台词 +- 话中有话,不直接说破 +- 通过语气和措辞暗示真实意图 +- 留白让读者自己体会 + +## 常见问题 + +### 避免过度网络化 +- 不要滥用网络用语 +- 考虑受众和场景 +- 保持可读性 + +### 平衡真实感和文学性 +- 真实对话不等于完全照搬 +- 需要艺术加工和提炼 +- 服务于故事和人物塑造 + +### 对话推动情节 +- 每句对话都应该有目的 +- 揭示信息、展现关系、推动剧情 +- 避免无效对话 + +## 工作流程 + +1. **理解需求**:明确场景、角色、目的 +2. **确定风格**:根据角色和场景选择对话模式 +3. **初稿创作**:快速写出对话框架 +4. **润色打磨**:加入细节、调整节奏、增强真实感 +5. **检查验证**:朗读检查流畅度,确保角色声音一致 \ No newline at end of file diff --git a/backend/skills_storage/user_skills/script-adapter/SKILL.md b/backend/skills_storage/user_skills/script-adapter/SKILL.md new file mode 100644 index 0000000..5315af2 --- /dev/null +++ b/backend/skills_storage/user_skills/script-adapter/SKILL.md @@ -0,0 +1,65 @@ +--- +name: script-adapter +description: Adapt novels, stories, or concepts into professional screenplay format (film/theater/TV). Use when user needs to transform narrative text into scripts, including scene breakdown, dialogue conversion, visual storytelling, and standard industry formatting. +--- + +# Script Adapter + +Transform source material into professional screenplays using industry-standard formatting and visual storytelling techniques. + +## Core Principles + +- **Show, Don't Tell**: Convert internal monologues and descriptions into visible actions and subtextual dialogue. +- **Visual Narrative**: Prioritize actions that can be seen and heard over abstract descriptions. +- **Economy of Words**: Keep action lines concise and dialogue sharp. + +## Adaptation Workflow + +### 1. Analyze Source Material +Identify and extract: +- Core conflict and theme +- Protagonist's arc and motivation +- Key plot points (inciting incident, climax, resolution) +- Essential characters (combine minor characters if necessary) + +### 2. Structure the Narrative +Map the source material to a standard structure: +- **Three-Act Structure**: Setup, Confrontation, Resolution +- **Scene List**: Break down the story into specific locations and timeframes +- **Pacing**: Ensure the flow works for visual media (faster than prose) + +### 3. Draft the Scene +For each scene: +1. **Slugline**: INT./EXT. LOCATION - DAY/NIGHT +2. **Action**: Describe what happens visually (present tense). +3. **Character Name**: Centered, uppercase. +4. **Dialogue**: What the character says. +5. **Parenthetical**: How the character says it (use sparingly). + +### 4. Refine and Format +- Check standard margins and spacing. +- Ensure all scenes drive the plot or reveal character. +- Remove exposition-heavy dialogue; replace with action. + +## Standard Format Guide + +```text +SLUGLINE: INT. LOCATION - DAY + +Action lines describe what the audience sees. Be specific and visual. + +CHARACTER NAME +(parenthetical direction) +Dialogue goes here. + +EXT. STREET - NIGHT + +More action. +``` + +## Key Adaptation Techniques + +- **Internal to External**: Convert "He felt sad" to "He stared at the floor, shoulders slumped." +- **Compression**: Merge multiple conversations from the book into one impactful scene. +- **Subtext**: Characters should rarely say exactly what they mean. Use silence and action to convey true feelings. +- **Enter Late, Leave Early**: Start scenes at the last possible moment and end them as soon as the main point is made. \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ce4b06a..f259cd1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,7 +18,7 @@ "react-dom": "^18.2.0", "react-markdown": "^9.0.1", "react-router-dom": "^6.20.0", - "react-syntax-highlighter": "^15.5.0", + "react-syntax-highlighter": "^16.1.0", "recharts": "^2.10.3", "remark-gfm": "^4.0.0", "socket.io-client": "^4.6.0", @@ -27,17 +27,17 @@ "devDependencies": { "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^8.54.0", + "@typescript-eslint/parser": "^8.54.0", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.16", - "eslint": "^8.55.0", - "eslint-plugin-react-hooks": "^4.6.0", + "eslint": "^9.39.2", + "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.5", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "typescript": "^5.2.2", - "vite": "^5.0.8" + "vite": "^7.3.1" } }, "node_modules/@alloc/quick-lru": { @@ -474,9 +474,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -487,13 +487,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -504,13 +504,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -521,13 +521,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -538,13 +538,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -555,13 +555,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -572,13 +572,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -589,13 +589,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -606,13 +606,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -623,13 +623,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -640,13 +640,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -657,13 +657,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -674,13 +674,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -691,13 +691,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -708,13 +708,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -725,13 +725,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -742,13 +742,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -759,13 +759,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -776,13 +793,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -793,13 +827,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -810,13 +861,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -827,13 +878,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -844,13 +895,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -861,7 +912,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -893,25 +944,90 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -928,6 +1044,16 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -942,53 +1068,64 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "brace-expansion": "^1.1.7" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": "*" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -1005,13 +1142,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", @@ -1806,6 +1949,12 @@ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "license": "MIT" + }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -1832,13 +1981,6 @@ "@types/react": "^18.0.0" } }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -1846,124 +1988,149 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/type-utils": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^2.4.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.54.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.54.0", + "@typescript-eslint/types": "^8.54.0", + "debug": "^4.4.3" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", "dev": true, "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1971,76 +2138,86 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@typescript-eslint/project-service": "8.54.0", + "@typescript-eslint/tsconfig-utils": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "node_modules/@typescript-eslint/utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@ungap/structured-clone": { @@ -2110,16 +2287,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2236,16 +2403,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2894,19 +3051,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -2914,19 +3058,6 @@ "dev": true, "license": "MIT" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -3026,9 +3157,9 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3036,32 +3167,35 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -3088,73 +3222,83 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react-refresh": { @@ -3168,9 +3312,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -3178,7 +3322,7 @@ "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3208,6 +3352,29 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3222,18 +3389,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3391,16 +3571,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -3434,18 +3614,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -3513,13 +3692,6 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3591,28 +3763,6 @@ "node": ">= 0.4" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3626,62 +3776,14 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3699,13 +3801,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3756,10 +3851,13 @@ } }, "node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -3806,68 +3904,37 @@ } }, "node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hastscript/node_modules/@types/hast": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", - "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2" - } - }, - "node_modules/hastscript/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, "license": "MIT" }, - "node_modules/hastscript/node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hastscript/node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, "license": "MIT", "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hastscript/node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "hermes-estree": "0.25.1" } }, "node_modules/highlight.js": { @@ -3896,9 +3963,9 @@ } }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -3932,25 +3999,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, "node_modules/inline-style-parser": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", @@ -4072,16 +4120,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -5215,9 +5253,9 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -5316,16 +5354,6 @@ "node": ">= 6" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -5424,16 +5452,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5451,16 +5469,6 @@ "dev": true, "license": "MIT" }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -6469,17 +6477,20 @@ } }, "node_modules/react-syntax-highlighter": { - "version": "15.6.6", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.6.tgz", - "integrity": "sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-16.1.0.tgz", + "integrity": "sha512-E40/hBiP5rCNwkeBN1vRP+xow1X0pndinO+z3h7HLsHyjztbyjfzNWNKuAsJj+7DLam9iT4AaaOZnueCU+Nplg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.3.1", + "@babel/runtime": "^7.28.4", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.30.0", - "refractor": "^3.6.0" + "refractor": "^5.0.0" + }, + "engines": { + "node": ">= 16.20.2" }, "peerDependencies": { "react": ">= 0.14.0" @@ -6557,121 +6568,21 @@ } }, "node_modules/refractor": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", - "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-5.0.0.tgz", + "integrity": "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==", "license": "MIT", "dependencies": { - "hastscript": "^6.0.0", - "parse-entities": "^2.0.0", - "prismjs": "~1.27.0" + "@types/hast": "^3.0.0", + "@types/prismjs": "^1.0.0", + "hastscript": "^9.0.0", + "parse-entities": "^4.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/refractor/node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "license": "MIT", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "license": "MIT", - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/prismjs": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -6786,23 +6697,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/rollup": { "version": "4.56.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.56.0.tgz", @@ -6926,16 +6820,6 @@ "node": ">=8" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/socket.io-client": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", @@ -7010,19 +6894,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -7147,13 +7018,6 @@ "node": ">=14.0.0" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -7280,16 +7144,16 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/ts-interface-checker": { @@ -7312,19 +7176,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -7534,21 +7385,24 @@ } }, "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -7557,19 +7411,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -7590,9 +7450,46 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7619,13 +7516,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", @@ -7655,15 +7545,6 @@ "node": ">=0.4.0" } }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -7684,6 +7565,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, "node_modules/zustand": { "version": "4.5.7", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", diff --git a/frontend/package.json b/frontend/package.json index c8b9933..3cb35b6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,35 +10,35 @@ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0" }, "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router-dom": "^6.20.0", - "antd": "^5.12.0", "@ant-design/icons": "^5.2.6", - "zustand": "^4.4.7", + "@monaco-editor/react": "^4.6.0", + "antd": "^5.12.0", "axios": "^1.6.2", - "socket.io-client": "^4.6.0", "dayjs": "^1.11.10", "monaco-editor": "^0.45.0", - "@monaco-editor/react": "^4.6.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-markdown": "^9.0.1", + "react-router-dom": "^6.20.0", + "react-syntax-highlighter": "^16.1.0", + "recharts": "^2.10.3", "remark-gfm": "^4.0.0", - "react-syntax-highlighter": "^15.5.0", - "recharts": "^2.10.3" + "socket.io-client": "^4.6.0", + "zustand": "^4.4.7" }, "devDependencies": { "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^8.54.0", + "@typescript-eslint/parser": "^8.54.0", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.16", - "eslint": "^8.55.0", - "eslint-plugin-react-hooks": "^4.6.0", + "eslint": "^9.39.2", + "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.5", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "typescript": "^5.2.2", - "vite": "^5.0.8" + "vite": "^7.3.1" } } diff --git a/frontend/src/components/SkillCreate.tsx b/frontend/src/components/SkillCreate.tsx index 2aff452..1b90e37 100644 --- a/frontend/src/components/SkillCreate.tsx +++ b/frontend/src/components/SkillCreate.tsx @@ -18,13 +18,11 @@ import { Modal, Form, Input, - Select, Button, Space, Card, Alert, message, - Spin, Typography, Tag, Upload, @@ -34,17 +32,14 @@ import { Row, Col, List, - Popconfirm, - Tooltip + Popconfirm } from 'antd' import { RobotOutlined, - CheckCircleOutlined, FileTextOutlined, UploadOutlined, LinkOutlined, GithubOutlined, - FilePdfOutlined, PlusOutlined, DeleteOutlined, EditOutlined, @@ -59,10 +54,9 @@ import { taskService } from '@/services/taskService' import TaskProgressTracker from '@/components/TaskProgressTracker' const { TextArea } = Input -const { Text, Title, Paragraph } = Typography +const { Text } = Typography const { Step } = Steps const { TabPane } = Tabs -const { Option } = Select interface SkillCreateProps { visible: boolean @@ -92,7 +86,7 @@ interface GeneratedSkill { type CreateStep = 'input' | 'generating' | 'preview' | 'references' | 'saving' -export const SkillCreate: React.FC = ({ +const SkillCreateComponent: React.FC = ({ visible, onClose, onSuccess, @@ -100,6 +94,14 @@ export const SkillCreate: React.FC = ({ }) => { const [form] = Form.useForm() + // 使用 ref 跟踪弹窗实际可见性(避免闭包问题) + const dialogVisibleRef = useRef(visible) + + // 当 visible prop 变化时更新 ref + useEffect(() => { + dialogVisibleRef.current = visible + }, [visible]) + // 步骤状态 const [step, setStep] = useState('input') const [aiDescription, setAiDescription] = useState('') @@ -118,13 +120,15 @@ export const SkillCreate: React.FC = ({ const [githubInput, setGithubInput] = useState('') const [manualFileName, setManualFileName] = useState('') const [manualContent, setManualContent] = useState('') - const [uploadedFiles, setUploadedFiles] = useState([]) // 预览ID(用于保存) const [previewId, setPreviewId] = useState(null) const contentPreviewRef = useRef(null) + // LocalStorage key for saving task state + const SKILL_TASK_STORAGE_KEY = 'skill_generation_task' + // 重置表单 const resetForm = () => { setStep('input') @@ -136,9 +140,8 @@ export const SkillCreate: React.FC = ({ setGithubInput('') setManualFileName('') setManualContent('') - setUploadedFiles([]) setPreviewId(null) - setCurrentTaskId(null) + // 不清除 currentTaskId,让用户可以继续跟踪任务 form.resetFields() } @@ -147,6 +150,61 @@ export const SkillCreate: React.FC = ({ if (editingSkillId && visible) { loadSkillForEdit(editingSkillId) } else if (visible) { + // 检查是否有正在进行的任务 + const savedTask = localStorage.getItem(SKILL_TASK_STORAGE_KEY) + if (savedTask) { + try { + const taskData = JSON.parse(savedTask) + // 检查任务是否是最近的(10分钟内) + const taskAge = Date.now() - taskData.timestamp + if (taskAge < 10 * 60 * 1000 && taskData.taskId && taskData.description) { + setCurrentTaskId(taskData.taskId) + setAiDescription(taskData.description) + setStep('generating') + setGenerating(true) + + // 继续轮询任务 + const pollSavedTask = async () => { + try { + const result = await taskService.pollTask(taskData.taskId, (progress) => { + console.log('Task progress:', progress) + }) + + if (result.success && result.result) { + const skillData = result.result + setGeneratedSkill({ + suggested_id: skillData.suggested_id, + suggested_name: skillData.suggested_name, + skill_content: skillData.skill_content, + category: skillData.category, + suggested_tags: skillData.suggested_tags, + explanation: skillData.explanation + }) + form.setFieldsValue({ content: skillData.skill_content }) + setStep('preview') + setGenerating(false) + setCurrentTaskId(null) + localStorage.removeItem(SKILL_TASK_STORAGE_KEY) + message.success('AI 生成成功!您可以预览和编辑内容') + } + } catch (error) { + message.error(`AI 生成失败: ${(error as Error).message}`) + setStep('input') + setGenerating(false) + setCurrentTaskId(null) + localStorage.removeItem(SKILL_TASK_STORAGE_KEY) + } + } + + pollSavedTask() + message.info('检测到正在进行的生成任务,正在继续...') + return + } + } catch (error) { + console.error('Failed to parse saved task:', error) + localStorage.removeItem(SKILL_TASK_STORAGE_KEY) + } + } resetForm() setStep('input') } @@ -154,6 +212,15 @@ export const SkillCreate: React.FC = ({ const loadSkillForEdit = async (skillId: string) => { try { + // 检查是否是虚拟的 task ID(正在生成中的 skill) + // 这种 ID 以 "task-" 开头,不是真实的 skill,不应该加载 + if (skillId.startsWith('task-')) { + console.log('[SkillCreate] Skipping load for virtual task ID:', skillId) + message.info('该 Skill 正在生成中,请等待生成完成后再编辑') + handleClose() + return + } + const result = await skillService.getSkillWithReferences(skillId, true) if (result) { const { skill, references: refs } = result @@ -194,6 +261,10 @@ export const SkillCreate: React.FC = ({ } const handleClose = () => { + // 如果有后台任务正在运行,可以关闭弹窗让任务继续在后台运行 + if (currentTaskId && generating) { + message.info('任务将在后台继续运行,您可以稍后再来查看结果') + } resetForm() onClose() } @@ -210,48 +281,96 @@ export const SkillCreate: React.FC = ({ try { // 创建异步任务 - const taskResult = await taskService.generateSkill({ + const response = await taskService.generateSkill({ description: aiDescription, temperature: 0.7 }) - setCurrentTaskId(taskResult.taskId) - message.success('任务已创建,正在生成中...') + const taskId = response.taskId + setCurrentTaskId(taskId) - // 轮询任务直到完成 - const result = await taskService.pollTask(taskResult.taskId, (progress) => { - // 可以在这里更新进度UI,如果需要的话 - console.log('Task progress:', progress) - }) + // 保存任务信息到 localStorage,以便关闭弹窗后恢复 + localStorage.setItem(SKILL_TASK_STORAGE_KEY, JSON.stringify({ + taskId, + description: aiDescription, + timestamp: Date.now() + })) - // 处理任务结果 - if (result.success && result.result) { - const skillData = result.result + message.success('任务已创建,正在后台生成中...您可以关闭此弹窗,生成完成后会自动保存') - setGeneratedSkill({ - suggested_id: skillData.suggested_id, - suggested_name: skillData.suggested_name, - skill_content: skillData.skill_content, - category: skillData.category, - suggested_tags: skillData.suggested_tags, - explanation: skillData.explanation - }) + // 启动后台轮询,但不阻塞 UI + const pollTaskInBackground = async () => { + try { + const result = await taskService.pollTask(taskId, (progress) => { + console.log('Task progress:', progress) + }) - form.setFieldsValue({ - content: skillData.skill_content - }) + // 任务完成后,如果弹窗还开着,显示结果 + if (result.success && result.result) { + const skillData = result.result + console.log('Task completed, skill data:', skillData) - setStep('preview') - message.success('AI 生成成功!您可以预览和编辑内容') - } else { - throw new Error(result.error || '生成失败') + // 清除 localStorage 中的任务信息 + localStorage.removeItem(SKILL_TASK_STORAGE_KEY) + + // 检查弹窗是否还打开(使用 ref 避免闭包问题) + if (dialogVisibleRef.current) { + // 弹窗打开:显示结果供用户查看 + // 注意:后端已经自动保存了,这里只是显示结果 + setGeneratedSkill({ + suggested_id: skillData.suggested_id, + suggested_name: skillData.suggested_name, + skill_content: skillData.skill_content, + category: skillData.category, + suggested_tags: skillData.suggested_tags, + explanation: skillData.explanation + }) + + form.setFieldsValue({ + content: skillData.skill_content + }) + + setStep('preview') + + const savedInfo = skillData.auto_saved + ? `${skillData.suggested_name} 已自动保存!(ID: ${skillData.saved_skill_id})` + : `${skillData.suggested_name} 生成完成!` + + message.success(savedInfo) + + // 通知父组件刷新列表 + onSuccess() + } else { + // 弹窗已关闭:后端已经自动保存,只需通知用户 + console.log('Dialog closed, skill was auto-saved by backend') + if (skillData.auto_saved) { + message.success(`${skillData.suggested_name} 已自动保存到 skills 列表!`) + // 通知父组件刷新列表 + onSuccess() + } else if (skillData.save_error) { + message.warning(`生成完成但自动保存失败: ${skillData.save_error}`) + } + } + } else { + throw new Error(result.error || '生成失败') + } + } catch (error) { + message.error(`AI 生成失败: ${(error as Error).message}`) + setStep('input') + // 清除 localStorage 中的任务信息 + localStorage.removeItem(SKILL_TASK_STORAGE_KEY) + } finally { + setGenerating(false) + setCurrentTaskId(null) + } } + + // 启动后台轮询 + pollTaskInBackground() } catch (error) { - message.error(`AI 生成失败: ${(error as Error).message}`) - setStep('input') - } finally { + message.error(`任务创建失败: ${(error as Error).message}`) setGenerating(false) - setCurrentTaskId(null) + setStep('input') } } @@ -280,6 +399,9 @@ export const SkillCreate: React.FC = ({ } // 使用AI调整内容 + const [refineModalVisible, setRefineModalVisible] = useState(false) + const [refinePrompt, setRefinePrompt] = useState('') + const handleRefineWithAI = async () => { const currentContent = form.getFieldValue('content') if (!currentContent) { @@ -287,17 +409,20 @@ export const SkillCreate: React.FC = ({ return } - const refinePrompt = await new Promise((resolve) => { - Modal.input({ - title: '输入调整需求', - placeholder: '例如:把内容改得更简洁、增加代码示例、优化描述...', - onOk: (value) => resolve(value || '') - }) - }) + setRefinePrompt('') + setRefineModalVisible(true) + } - if (!refinePrompt) return + const confirmRefineWithAI = async () => { + if (!refinePrompt.trim()) { + message.warning('请输入调整需求') + return + } + const currentContent = form.getFieldValue('content') + setRefineModalVisible(false) setGenerating(true) + try { const result = await skillService.refineSkill(currentContent, refinePrompt, 0.7) @@ -535,6 +660,7 @@ export const SkillCreate: React.FC = ({ } return ( + <> @@ -599,15 +725,28 @@ export const SkillCreate: React.FC = ({ {/* ========== 生成中 ========== */} {step === 'generating' && currentTaskId && ( + { + onComplete={() => { // 任务完成后的处理逻辑已经在 handleGenerate 中了 }} onError={(error) => { message.error(`生成失败: ${error}`) }} /> +
+ +
)} @@ -936,7 +1075,29 @@ export const SkillCreate: React.FC = ({ )}
+ + {/* AI 调整弹窗 */} + setRefineModalVisible(false)} + okText="开始调整" + cancelText="取消" + > + +