diff --git a/README.md b/README.md index 79f1bab..16139d4 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,168 @@ # Creator Studio -AI 驱动的小说写作助手。 +Creator Studio 是一个面向长篇小说创作的桌面应用,基于 Tauri、React、TypeScript 和 Rust 构建。项目当前重点覆盖章节管理、正文编辑、AI 对话与续写,以及围绕安装包、默认模型和编辑器交互建立的回归测试体系。 -## 项目简介 +## 安装 -Creator Studio 面向长篇小说/系列创作场景,提供“项目-章节”结构化管理、编辑器能力,以及围绕写作流程设计的 AI 讨论与 AI 续写能力,帮助你更稳定地推进写作。 +### Windows 用户 -## 功能特性 +- 优先使用安装包版本,不要直接运行 `src-tauri/target/debug/` 下的调试产物。 +- 当前最新版安装包默认同步到项目根目录 [`release/`](C:/Users/16053/proj/07-story/Creator-Studio/release)。 +- Windows 常用产物: + - `release/CreatorAI__x64_en-US.msi` + - `release/CreatorAI__x64-setup.exe` -- **章节管理**:项目创建/打开、章节增删改查、章节列表与排序、导入 txt 拆章 -- **写作编辑**:Undo/Redo、字数统计、自动保存 -- **AI 讨论**:围绕剧情、人物、世界观进行多轮讨论与方案推演 -- **AI 续写**:基于当前章节与上下文续写,可选择插入到正文 -- **写作预设**:风格/口吻/视角、角色设定、禁用词等写作约束与偏好 +### macOS 用户 -## 安装说明 +- macOS 打包产物会出现在项目根目录 `release/`,常见文件为 `.dmg`。 -### macOS(使用 .dmg) +### 默认 AI Provider -1. 下载并打开 `.dmg` 安装包 -2. 将应用拖拽到“Applications/应用程序” -3. 首次运行如遇到系统拦截,可在“系统设置 → 隐私与安全性”中允许打开 +- 应用内置默认 Provider 配置,预置 Base URL、Provider 类型和默认模型。 +- 出于安全原因,软件不再内置任何真实 API key。 +- 首次使用 AI 前,用户需要在设置中为当前 Provider 手工填写自己的 API key。 +- 当前默认配置: + - Base URL: `https://dashscope.aliyuncs.com/compatible-mode/v1` + - Model: `qwen-plus` -> 说明:当前打包产物的应用/安装包名称可能显示为 `CreatorAI`(由 `src-tauri/tauri.conf.json` 的 `productName` 决定)。 +## 开发 -### 从源码运行(开发者) +### 环境要求 -前置依赖: -- Node.js(建议 18+) -- Rust(stable) -- Bun(用于编译内置 `ai-engine` sidecar;不想装 Bun 可直接使用发布版应用) -- macOS 需要 Xcode Command Line Tools:`xcode-select --install` +- Node.js 18+ +- npm +- Rust stable +- Windows 下需要可用的 Rust MSVC 工具链 -安装依赖: +### 安装依赖 ```bash npm install ``` -启动开发模式(Tauri): +### 启动开发环境 ```bash npm run tauri:dev ``` -构建安装包(macOS .dmg): +说明: +- 该命令会先构建 AI sidecar,再启动前端和 Tauri 桌面壳。 +- 不要把调试版可执行文件当成发布版验证结果;Windows demo、安装包联调要使用安装版或 release 版。 + +## 测试 + +项目已经拆出独立测试子工程 [`test-suite/`](C:/Users/16053/proj/07-story/Creator-Studio/test-suite),后续新增功能和修 bug 都应优先在这里补测试,而不是继续堆临时脚本。 + +### 常用测试命令 + +```bash +npm run test:default-provider +npm run test:ai-engine-sidecar +npm run test:no-hardcoded-secrets +npm run test:editor-shortcuts +npm run test:editor-e2e +npm run test:windows-demo +npm run test:regression +``` + +### 测试要求 + +- 修复 bug 时,优先补一个可复现该问题的测试用例。 +- 安装包问题必须补安装链路或运行链路测试。 +- 编辑器交互问题必须补实际交互回归测试,必要时走 Playwright。 +- 凡是安全修复,都必须补对应的仓库扫描或回归校验。 +- 技术说明同时写入 `bug/` 和 `test-suite/docs/`,保证后续模型可直接接手。 + +详细规则见: +- [test-suite/README.md](C:/Users/16053/proj/07-story/Creator-Studio/test-suite/README.md) +- [test-suite/docs/testing-rules.md](C:/Users/16053/proj/07-story/Creator-Studio/test-suite/docs/testing-rules.md) + +## 打包 + +### 本地构建 ```bash npm run tauri:build ``` -## 使用说明 +该命令会执行三件事: +- 构建 AI engine sidecar +- 执行 Tauri release build +- 将最终安装包同步复制到项目根目录 `release/` + +### Tauri 实际输出目录 + +Tauri 原始 bundle 输出目录不是根目录 `release/`,而是: + +- `src-tauri/target/release/bundle/msi/` +- `src-tauri/target/release/bundle/nsis/` +- macOS 对应 `src-tauri/target/release/bundle/dmg/` + +项目根目录 `release/` 的作用是: + +- 作为统一交付目录 +- 方便人工验收 +- 方便后续上传到 GitHub 或发给测试同学 + +### 打包前检查 + +- 确认版本号已更新 +- 先跑核心回归测试 +- 确认默认 Provider 配置存在且模型选择正常 +- 确认没有硬编码 API key +- 确认安装后 AI 引擎能正常启动 +- 确认不会弹黑色 shell 窗口 + +相关记录见: +- [bug/package_building_notes.md](C:/Users/16053/proj/07-story/Creator-Studio/bug/package_building_notes.md) +- [bug/default_provider_dashscope_qwen_demo.md](C:/Users/16053/proj/07-story/Creator-Studio/bug/default_provider_dashscope_qwen_demo.md) + +## 发布 + +### 当前约定 + +- 每次完成可交付构建后,把最新安装包同步到项目根目录 `release/` +- 对外说明时,以 `release/` 中的产物为准 +- 不把 Tauri 内部产物路径直接发给最终用户 +- 不得把任何真实 API key 写入代码、文档、测试样例或安装包默认配置 + +### 推荐发布流程 + +1. 更新版本号 +2. 运行核心回归测试 +3. 执行 `npm run tauri:build` +4. 验证 `release/` 中的最新 MSI/EXE +5. 安装后做一次实际启动与 AI 请求验证 +6. 确认 GitHub Release 附件不包含敏感信息 +7. 再上传到 GitHub Release 或交付渠道 + +如果只是需要本地找到安装包: + +- 根目录交付目录:[`release/`](C:/Users/16053/proj/07-story/Creator-Studio/release) +- Tauri 原始输出目录:[`src-tauri/target/release/bundle/`](C:/Users/16053/proj/07-story/Creator-Studio/src-tauri/target/release/bundle) -1. **创建/打开项目**:选择一个工作目录作为项目根目录 -2. **导入或新建章节**:可导入 txt 自动拆章,或手动新建章节 -3. **编辑写作**:在编辑器中完成正文创作,应用自动保存/撤销重做等能力 -4. **AI 面板**: - - 选择“讨论”模式:梳理情节、推演冲突、完善设定 - - 选择“续写”模式:基于上下文生成续写内容并插入到正文 -5. **写作预设**:为不同作品配置风格、角色设定与写作约束,提升一致性 +## 目录说明 -## 知识库(RAG) +- [`src/`](C:/Users/16053/proj/07-story/Creator-Studio/src):前端界面与编辑器逻辑 +- [`src-tauri/`](C:/Users/16053/proj/07-story/Creator-Studio/src-tauri):Tauri 后端、配置和 sidecar 启动逻辑 +- [`packages/ai-engine/`](C:/Users/16053/proj/07-story/Creator-Studio/packages/ai-engine):AI 引擎源码 +- [`scripts/`](C:/Users/16053/proj/07-story/Creator-Studio/scripts):构建与产物同步脚本 +- [`test-suite/`](C:/Users/16053/proj/07-story/Creator-Studio/test-suite):独立测试工程 +- [`bug/`](C:/Users/16053/proj/07-story/Creator-Studio/bug):缺陷记录、修复注释、打包与回归说明 +- [`release/`](C:/Users/16053/proj/07-story/Creator-Studio/release):同步后的交付产物目录 -- 把人物/设定/时间线等资料放在项目目录的 `knowledge/`(支持 `.md/.txt`),在侧边栏「知识库」里点击“构建索引”。 -- 索引与缓存默认保存到项目目录的 `.creatorai/rag/`。 -- 若自动下载嵌入模型失败,可设置环境变量 `HF_ENDPOINT`(例如 `https://hf-mirror.com`),或手动下载模型文件放到 `.creatorai/rag/models/Xenova/bge-small-zh-v1.5/`。 +## 最近重点修复 -## 技术栈 +- 修复安装版 AI 引擎启动失败问题 +- 修复安装后频繁弹出黑色 shell 窗口问题 +- 修复编辑器自动保存后内容被旧状态覆盖的问题 +- 补齐 `Ctrl+S`、`Ctrl+Z`、`Ctrl+Y`、`Ctrl+Shift+Z`、`Ctrl+A` 等常用快捷键 +- 建立 Windows demo、默认 Provider、AI sidecar、编辑器交互回归测试 +- 移除硬编码 API key,并加入泄露密钥清理和仓库扫描测试 -- Tauri -- React -- TypeScript -- Rust +对应文档: +- [bug/editor_autosave_content_loss.md](C:/Users/16053/proj/07-story/Creator-Studio/bug/editor_autosave_content_loss.md) +- [bug/editor_shortcuts_improvement.md](C:/Users/16053/proj/07-story/Creator-Studio/bug/editor_shortcuts_improvement.md) +- [bug/editor_interaction_regression_tests.md](C:/Users/16053/proj/07-story/Creator-Studio/bug/editor_interaction_regression_tests.md) +- [bug/windows_demo_server_connection_note.md](C:/Users/16053/proj/07-story/Creator-Studio/bug/windows_demo_server_connection_note.md) diff --git a/bug/MLComputePlan_link_error_solution.md b/bug/MLComputePlan_link_error_solution.md new file mode 100644 index 0000000..39b0612 --- /dev/null +++ b/bug/MLComputePlan_link_error_solution.md @@ -0,0 +1,47 @@ +# MLComputePlan 符号链接错误解决方案 + +## 问题描述 +在 macOS 上编译包含 ONNX Runtime 的 Rust 项目时,出现 `MLComputePlan` 符号未找到的链接错误: +``` +error: could not compile `creatorai-v2` (lib) due to 1 previous error; 2 warnings emitted +``` + +## 问题原因 +- `MLComputePlan` 类仅在 macOS 13.3+ 版本中可用 +- ONNX Runtime (ort) 库需要访问这个类,但在较低版本的 macOS 上不存在 +- 编译器试图链接到较低版本的 macOS,导致找不到该符号 + +## 解决方案 +### 1. 添加弱链接 +在 [build.rs](file:///Users/yuhanwen/Desktop/work/01-story/Creator-Studio/src-tauri/build.rs) 文件中添加对 MLCompute 框架的弱链接: +```rust +if cfg!(target_os = "macos") { + // 添加链接器参数以支持 CoreML 的新功能 + println!("cargo:rustc-link-arg=-mmacosx-version-min=13.3"); + + // 如果是 ARM64 架构,添加额外的链接参数 + if cfg!(target_arch = "aarch64") { + println!("cargo:rustc-link-arg=-stdlib=libc++"); + } + + // 添加弱链接,解决 MLComputePlan 符号问题 + println!("cargo:rustc-link-arg=-Wl,-weak_framework,MLCompute"); +} +``` + +### 2. 添加缺失的依赖项 +在 [Cargo.toml](file:///Users/yuhanwen/Desktop/work/01-story/Creator-Studio/src-tauri/Cargo.toml) 中添加项目代码中使用但未声明的依赖: +```toml +regex = "1.10.4" +keyring = "2.3.3" +bincode = "1.3.3" +uuid = { version = "1.0.0", features = ["v4", "serde"] } +``` + +## 修复效果 +- 项目能够在 macOS 上成功编译 +- 应用可以正常运行,支持在不同版本的 macOS 上使用 +- AI 推理功能正常工作 + +## 技术原理 +使用 `-Wl,-weak_framework,MLCompute` 链接参数允许应用在缺少 MLCompute 框架的旧系统上运行,同时在支持的系统上充分利用该框架提供的功能。 \ No newline at end of file diff --git a/bug/build_packaging_notes.md b/bug/build_packaging_notes.md new file mode 100644 index 0000000..adac600 --- /dev/null +++ b/bug/build_packaging_notes.md @@ -0,0 +1,46 @@ +# 构建和打包说明文档 + +## 构建过程记录 + +### 构建环境 +- 操作系统: macOS +- 项目类型: Tauri 桌面应用程序 +- 应用名称: CreatorAI +- 版本号: 0.1.12 + +### 构建命令 +使用 `tauri build` 命令进行构建和打包。 + +### 构建时间 +- 总构建时间: 3分49秒 +- 这是一个包含AI推理库的大型Rust项目,因此构建时间相对较长 + +### 打包产物 +成功生成以下文件: +1. macOS 应用程序包: `/Users/yuhanwen/Desktop/work/01-story/Creator-Studio/src-tauri/target/release/bundle/macos/CreatorAI.app` +2. macOS DMG 安装包: `/Users/yuhanwen/Desktop/work/01-story/Creator-Studio/src-tauri/target/release/bundle/dmg/CreatorAI_0.1.12_aarch64.dmg` + +该DMG安装包已复制到release目录中。 + +## 关于Windows MSI包的说明 + +**重要提示**: 在当前的macOS环境中无法创建Windows MSI安装包。这是因为: + +1. 平台限制: Tauri的打包功能是平台特定的,只能为当前操作系统创建安装包 +2. Windows MSI包需要在Windows环境下构建 +3. macOS无法原生编译或创建Windows特定的安装包格式 + +如果您需要Windows MSI安装包,您需要: +- 在Windows系统上运行 `tauri build` +- 或者使用交叉编译工具链 +- 或者设置CI/CD流水线,在Windows构建代理上生成MSI包 + +## 项目特点 + +此项目包含大量AI推理相关的依赖库,包括: +- ONNX Runtime +- Tokenizers (v0.22.2 和 v0.15.2) +- FastEmbed (v5.12.1) +- 各种图像处理和机器学习库 + +这些库导致了较长的构建时间,但提供了强大的AI功能支持。 \ No newline at end of file diff --git a/bug/default_provider_dashscope_qwen_demo.md b/bug/default_provider_dashscope_qwen_demo.md new file mode 100644 index 0000000..aa98dbf --- /dev/null +++ b/bug/default_provider_dashscope_qwen_demo.md @@ -0,0 +1,41 @@ +# DashScope 默认 Provider 安全说明 + +## 当前策略 + +- 软件仍然内置一个默认 DashScope Provider。 +- 该默认 Provider 只预置以下非敏感配置: + - Provider ID: `builtin_dashscope_qwen_demo` + - Provider Name: `DashScope Qwen Demo` + - Base URL: `https://dashscope.aliyuncs.com/compatible-mode/v1` + - Model: `qwen-plus` + - Provider Type: `openai-compatible` + +## 安全调整 + +- 已移除代码中的硬编码 API key。 +- 已移除首次加载时自动把默认 key 写入系统 keyring 的逻辑。 +- 已加入旧泄露 key 清理逻辑: + - 如果本地 keyring 中检测到历史泄露 key,会自动删除。 + +## 为什么这样改 + +- 真实 API key 一旦进入源码仓库、安装包、公开 Release 或日志,就存在被盗刷风险。 +- 默认 Provider 可以保留,方便用户少填一层 URL 和模型配置。 +- 但 API key 必须改为用户本地自行配置,不能继续跟随软件分发。 + +## 用户侧行为 + +- 首次使用 AI 前,需要在设置中为当前 Provider 手工填写自己的 API key。 +- API key 仍然保存在系统凭据库,不写入普通配置文件。 + +## 回归要求 + +- 仓库中不得出现任何真实 API key 字面量。 +- 安全修复后必须补测试,当前已新增: + - `npm run test:no-hardcoded-secrets` + - `npm run test:regression` + +## 额外处理建议 + +- 已经暴露过的 key 不应继续使用。 +- 必须到供应商控制台立即废弃旧 key,并重新生成新 key。 diff --git a/bug/editor_autosave_content_loss.md b/bug/editor_autosave_content_loss.md new file mode 100644 index 0000000..2f29966 --- /dev/null +++ b/bug/editor_autosave_content_loss.md @@ -0,0 +1,27 @@ +# 编辑器自动保存后内容被旧状态覆盖 + +## 严重级别 +- 严重 + +## 问题现象 +- 在文本编辑框持续输入内容后,停顿触发自动保存,约一分钟内可能出现整段文本被清空或回退到旧版本的情况。 +- 用户无法稳定保留新输入内容,属于高风险数据丢失缺陷。 + +## 根因 +- 编辑器自动保存成功后,子组件的未保存状态会切换回 `false`。 +- 这时父组件 `MainLayout` 中传给编辑器的 `initialContent` 仍然是保存前的旧值。 +- 编辑器的同步逻辑在“当前无未保存改动”时会用 `initialContent` 重置编辑器内容,导致刚刚保存成功的新文本被旧内容覆盖。 + +## 修复方案 +- 在 [`src/layouts/MainLayout.tsx`](c:\Users\16053\proj\07-story\Creator-Studio\src\layouts\MainLayout.tsx) 的 `handleSave` 中,Tauri 保存成功后立刻同步: + - `setChapterContent(content)` + - `setDraftContent(content)` +- 这样编辑器在自动保存完成后收到的 `initialContent` 已经是最新内容,不会再回滚到旧文本。 + +## 验证方式 +- 执行 `npm run test:regression` +- 手工验证: + 1. 打开任一项目章节。 + 2. 连续输入至少 1 分钟。 + 3. 停止输入,等待自动保存完成。 + 4. 确认文本未消失,重新切换章节后内容仍然存在。 diff --git a/bug/editor_interaction_regression_tests.md b/bug/editor_interaction_regression_tests.md new file mode 100644 index 0000000..f9fddd3 --- /dev/null +++ b/bug/editor_interaction_regression_tests.md @@ -0,0 +1,33 @@ +# 编辑器实际交互回归测试 + +## 背景 + +- 仅做源码静态检查不足以覆盖真实键盘交互问题。 +- 编辑器快捷键、选区、保存链路需要浏览器级自动化测试。 + +## 本次新增 + +- 增加编辑器测试页: + - [`editor-harness.html`](c:\Users\16053\proj\07-story\Creator-Studio\editor-harness.html) + - [`src/testHarness/editorHarness.tsx`](c:\Users\16053\proj\07-story\Creator-Studio\src\testHarness\editorHarness.tsx) +- 增加 Playwright 配置: + - [`playwright.config.ts`](c:\Users\16053\proj\07-story\Creator-Studio\playwright.config.ts) +- 增加实际交互用例: + - [`test-suite/e2e/editor-shortcuts.spec.ts`](c:\Users\16053\proj\07-story\Creator-Studio\test-suite\e2e\editor-shortcuts.spec.ts) + +## 覆盖内容 + +- `Ctrl+S` 保存 +- `Ctrl+Z` 撤销 +- `Ctrl+Y` 重做 +- `Ctrl+Shift+Z` 重做 +- `Ctrl+A` 全选后整体替换 + +## 技术注释 + +- 为了让测试稳定,测试页关闭了编辑器的 AI 行内补全,避免异步补全干扰键盘事件验证。 +- 测试不依赖 Tauri,直接跑浏览器级页面,因此更适合在调试阶段高频执行。 + +## 运行方式 + +- `npm run test:editor-e2e` diff --git a/bug/editor_shortcuts_improvement.md b/bug/editor_shortcuts_improvement.md new file mode 100644 index 0000000..94f5ac5 --- /dev/null +++ b/bug/editor_shortcuts_improvement.md @@ -0,0 +1,32 @@ +# 编辑器常用快捷键体验补强 + +## 背景 + +- 用户反馈文本编辑器中的 `Ctrl+S`、`Ctrl+Z` 等常用快捷键体验不稳定,不符合桌面编辑器预期。 + +## 处理目标 + +- 让编辑器快捷键更贴近 Windows 常见写作软件和代码编辑器习惯。 +- 把这类问题固定成测试和文档要求,避免后续退化。 + +## 本次改动 + +- 在 [`src/components/Editor/Editor.tsx`](c:\Users\16053\proj\07-story\Creator-Studio\src\components\Editor\Editor.tsx) 中显式绑定: + - `Mod-z` + - `Mod-Shift-z` + - Windows/Linux `Ctrl-y` + - `Mod-a` + - `Mod-s` + - Windows/Linux `Ctrl-Shift-s` +- 在 [`src/components/Editor/EditorHeader.tsx`](c:\Users\16053\proj\07-story\Creator-Studio\src\components\Editor\EditorHeader.tsx) 中同步更新快捷键提示文案。 + +## 技术注释 + +- CodeMirror 官方已有 `historyKeymap`,但桌面产品中用户对 `Ctrl+Y` 的预期很强,因此需要显式覆盖。 +- 全选通过 `EditorSelection.single(0, view.state.doc.length)` 直接选中全文。 +- 显式快捷键要设置 `preventDefault: true`,否则浏览器默认行为可能干扰编辑器交互。 + +## 验证 + +- `npm run test:editor-shortcuts` +- `npm run build` diff --git a/bug/package_building_notes.md b/bug/package_building_notes.md new file mode 100644 index 0000000..ee30f29 --- /dev/null +++ b/bug/package_building_notes.md @@ -0,0 +1,86 @@ +# 安装包与发布说明 + +## 当前结论 + +- Windows 安装包必须在 Windows 环境下构建和验证。 +- Tauri 原始打包输出目录是: + - `src-tauri/target/release/bundle/msi/` + - `src-tauri/target/release/bundle/nsis/` +- 项目根目录的 `release/` 只是二次同步目录,方便直接取包,不是 Tauri 原始输出目录。 + +## 当前固定规则 + +- 每次执行 `npm run tauri:build` 后,安装包要自动同步到 `release/`。 +- 对外发包时,统一从 `release/` 目录取包。 +- Windows 版本号必须递增,不能反复用同一版本覆盖调试安装问题。 +- 修复安装版问题时,不能只验证源码目录或 `src-tauri/target/release/creatorai-v2.exe`,必须实际验证安装版。 + +## 当前构建入口 + +- `npm run tauri:build` + +它会执行: + +1. 构建 `ai-engine` sidecar +2. 构建 Tauri 发布版 +3. 生成 MSI / NSIS 安装包 +4. 将安装包复制到 `release/` + +## 当前关键实现 + +- `scripts/build-ai-engine.mjs` + - 使用 `esbuild` 将 `ai-engine` 打成单文件 bundle + - 避免安装版运行时缺少 `node_modules` +- `scripts/copy-release-artifacts.mjs` + - 将 `src-tauri/target/release/bundle/` 下的安装包同步到 `release/` + +## Windows 安装版已知注意事项 + +- 安装目录不一定是 `C:\Program Files\CreatorAI` +- 当前机器上的 MSI 实际安装路径可能是: + - `C:\Users\<用户名>\AppData\Local\CreatorAI` +- 安装后要优先检查: + - `creatorai-v2.exe` + - `bin/ai-engine.js` +- AI 引擎查找顺序必须优先 `安装目录/bin` + +## 本轮修复要点 + +### 1. AI 引擎安装版路径修复 + +- 安装版中 `ai-engine.js` 位于 `安装目录/bin/ai-engine.js` +- Tauri 侧查找逻辑已调整为优先搜索 `exe_dir/bin` +- 避免先误命中根目录里的旧 `ai-engine.exe` + +### 2. AI 引擎黑窗修复 + +- Windows 上启动 `node ai-engine.js` 时使用无控制台窗口方式 +- 避免每次调用大模型时弹出黑色 shell 窗口 + +### 3. 重装清理规则 + +- 正常重启软件不清理聊天界面状态 +- 新安装/新版本首次启动时,清理旧版本遗留的本地 UI 状态 +- 后端不再直接删除当前版本自己的 WebView 目录,避免安装后闪退 + +## 安装版验证步骤 + +每次修复安装包相关问题后,必须至少完成以下验证: + +1. `cargo test --manifest-path src-tauri/Cargo.toml --lib -- --nocapture` +2. `npm run test:regression` +3. `npm run tauri:build` +4. 用新 MSI 实际安装 +5. 启动安装后的 `creatorai-v2.exe` +6. 验证: + - 应用能正常启动 + - 调用 AI 不报 `AI 引擎启动失败` + - 不弹黑色 shell 窗口 + - 重装后旧聊天界面状态已清理 + +## 当前推荐取包路径 + +- MSI: + - `release/CreatorAI__x64_en-US.msi` +- NSIS: + - `release/CreatorAI__x64-setup.exe` diff --git a/bug/windows_demo_server_connection_note.md b/bug/windows_demo_server_connection_note.md new file mode 100644 index 0000000..e6916df --- /dev/null +++ b/bug/windows_demo_server_connection_note.md @@ -0,0 +1,28 @@ +# Windows 演示启动时出现“无法连接服务器” + +## 问题现象 + +- 在 Windows 上直接打开应用后,界面提示无法连接服务器。 + +## 实际根因 + +- 启动的是开发态调试产物 [`src-tauri/target/debug/creatorai-v2.exe`](c:\Users\16053\proj\07-story\Creator-Studio\src-tauri\target\debug\creatorai-v2.exe)。 +- 该产物会依赖 [`src-tauri/tauri.conf.json`](c:\Users\16053\proj\07-story\Creator-Studio\src-tauri\tauri.conf.json) 中的 `devUrl`,当前值是 `http://localhost:1420`。 +- 在没有运行前端开发服务器的情况下,应用会表现为“无法连接服务器”。 + +## 正确做法 + +- Windows 演示时应启动安装版或发布版程序,而不是调试产物。 +- 本机已安装的正确路径是: + - `C:\Program Files\CreatorAI\creatorai-v2.exe` + +## 测试固化 + +- 已在 [`test-suite/cases/windows-demo.mjs`](c:\Users\16053\proj\07-story\Creator-Studio\test-suite\cases\windows-demo.mjs) 增加 Windows 演示启动检查项。 +- 运行命令: + - `npm run test:windows-demo` + +## 技术注释 + +- 这个问题属于“启动方式错误”而不是“业务逻辑缺陷”。 +- 以后如果再出现类似问题,先判断当前运行的是开发态、调试态还是发布态产物,再判断是否是真正的功能 bug。 diff --git "a/docs/T2.6-\351\252\214\350\257\201\346\212\245\345\221\212.md" "b/docs/T2.6-\351\252\214\350\257\201\346\212\245\345\221\212.md" index bf77911..a1787cd 100644 --- "a/docs/T2.6-\351\252\214\350\257\201\346\212\245\345\221\212.md" +++ "b/docs/T2.6-\351\252\214\350\257\201\346\212\245\345\221\212.md" @@ -4,7 +4,7 @@ - 日期:2026-02-02 - 启动方式:`npm run tauri dev`(Vite: `http://localhost:1420/`) - Base URL:http://127.0.0.1:3002/geminicli/v1 -- API Key:sk-XnbHbzBOmPYGHgL_4Mg8zRcoBIb2gVpJiuO0eSifyyCUV2Twz2c4SljcNCo +- API Key: - Model:gemini-3-flash-preview - Provider Type:openai-compatible(OpenAI 兼容端点) diff --git a/editor-harness.html b/editor-harness.html new file mode 100644 index 0000000..73ff317 --- /dev/null +++ b/editor-harness.html @@ -0,0 +1,12 @@ + + + + + + Editor Harness + + +
+ + + diff --git a/package-lock.json b/package-lock.json index c632537..69a6fb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "creatorai-v2", - "version": "0.1.0", + "version": "0.1.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "creatorai-v2", - "version": "0.1.0", + "version": "0.1.12", "dependencies": { "@ant-design/icons": "^6.1.0", "@codemirror/commands": "^6.8.1", @@ -21,12 +21,13 @@ "zustand": "^5.0.11" }, "devDependencies": { + "@playwright/test": "^1.58.2", "@tauri-apps/cli": "2.10.0", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", - "@vitejs/plugin-react": "^4.6.0", + "@vitejs/plugin-react": "^4.3.1", "typescript": "~5.8.3", - "vite": "^7.0.4" + "vite": "^5.4.10" } }, "node_modules/@ant-design/colors": { @@ -473,445 +474,371 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "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==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { - "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "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==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { - "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "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==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "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==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { - "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "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": ">=12" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "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": ">=12" } }, "node_modules/@esbuild/openbsd-x64": { - "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "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": ">=12" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "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==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { - "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "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==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { - "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@jridgewell/gen-mapping": { @@ -994,6 +921,22 @@ "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", "license": "MIT" }, + "node_modules/@playwright/test": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", + "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@rc-component/async-validator": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.1.0.tgz", @@ -1707,358 +1650,326 @@ "react-dom": ">=16.9.0" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openharmony" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2358,8 +2269,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/react": { "version": "19.2.10", @@ -2382,24 +2292,22 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", + "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", + "@babel/core": "^7.24.5", + "@babel/plugin-transform-react-jsx-self": "^7.24.5", + "@babel/plugin-transform-react-jsx-source": "^7.24.1", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "react-refresh": "^0.14.2" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "vite": "^4.2.0 || ^5.0.0" } }, "node_modules/antd": { @@ -2597,45 +2505,41 @@ "license": "ISC" }, "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18" + "node": ">=12" }, "optionalDependencies": { - "@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" + "@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" } }, "node_modules/escalade": { @@ -2648,31 +2552,12 @@ "node": ">=6" } }, - "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/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -2767,7 +2652,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -2789,23 +2673,57 @@ "dev": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, "engines": { - "node": ">=12" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -2821,7 +2739,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -2859,21 +2776,19 @@ "license": "MIT" }, "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.8" }, @@ -2885,31 +2800,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, @@ -2943,7 +2858,6 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -2975,23 +2889,6 @@ "node": ">=12.22" } }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -3038,24 +2935,20 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "5.4.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", + "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", "dev": true, - "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -3064,25 +2957,19 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", "lightningcss": "^1.21.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" + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, - "jiti": { - "optional": true - }, "less": { "optional": true }, @@ -3103,12 +2990,6 @@ }, "terser": { "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true } } }, diff --git a/package.json b/package.json index d5b6324..57dd296 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,23 @@ { "name": "creatorai-v2", "private": true, - "version": "0.1.12", + "version": "0.1.15", "type": "module", "scripts": { "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", + "test:ai-engine-sidecar": "node test-suite/run.mjs ai-engine-sidecar", + "test:editor-e2e": "playwright test", + "test:default-provider": "node test-suite/run.mjs default-provider", + "test:editor-shortcuts": "node test-suite/run.mjs editor-shortcuts", + "test:no-hardcoded-secrets": "node test-suite/run.mjs no-hardcoded-secrets", + "test:regression": "node test-suite/run.mjs regression", + "test:windows-demo": "node test-suite/run.mjs windows-demo", "tauri": "tauri", "ai-engine:build": "node scripts/build-ai-engine.mjs", "tauri:dev": "npm run ai-engine:build && tauri dev", - "tauri:build": "npm run ai-engine:build && CI=true tauri build" + "tauri:build": "npm run ai-engine:build && tauri build && node scripts/copy-release-artifacts.mjs" }, "dependencies": { "@ant-design/icons": "^6.1.0", @@ -26,11 +33,12 @@ "zustand": "^5.0.11" }, "devDependencies": { + "@playwright/test": "^1.58.2", "@tauri-apps/cli": "2.10.0", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", - "@vitejs/plugin-react": "^4.6.0", + "@vitejs/plugin-react": "^4.3.1", "typescript": "~5.8.3", - "vite": "^7.0.4" + "vite": "^5.4.10" } } diff --git a/packages/ai-engine/package-lock.json b/packages/ai-engine/package-lock.json new file mode 100644 index 0000000..ec42231 --- /dev/null +++ b/packages/ai-engine/package-lock.json @@ -0,0 +1,1753 @@ +{ + "name": "@creatorai/ai-engine", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@creatorai/ai-engine", + "version": "0.1.0", + "dependencies": { + "@ai-sdk/openai-compatible": "^0.1.0", + "ai": "^4.0.0", + "zod": "^3.23.0" + }, + "bin": { + "ai-engine": "src/cli.ts" + }, + "devDependencies": { + "@types/bun": "latest", + "tsup": "^8.5.1", + "typescript": "^5.0.0" + } + }, + "node_modules/@ai-sdk/openai-compatible": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai-compatible/-/openai-compatible-0.1.17.tgz", + "integrity": "sha512-e60+yxQ29e8RlsTWBW4kLuQJMpVJzH5+cpOeUXLXU6M9wc8BOQCyYg4jYh2ldnfvYCKXYxb2kYeLW7L9fqhhMw==", + "dependencies": { + "@ai-sdk/provider": "1.0.12", + "@ai-sdk/provider-utils": "2.1.15" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.0.0" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.0.12.tgz", + "integrity": "sha512-88Uu1zJIE1UUOVJWfE2ybJXgiH8JJ97QY9fbmplErEbfa/k/1kF+tWMVAAJolF2aOGmazQGyQLhv4I9CCuVACw==", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.1.15.tgz", + "integrity": "sha512-ndMVtDm2xS86t45CJZSfyl7UblZFewRB8gZkXQHeNi7BhjCYkhE+XQMwfDl6UOAO7kaV60IC1R4JLDWxWiiHug==", + "dependencies": { + "@ai-sdk/provider": "1.0.12", + "eventsource-parser": "^3.0.0", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/react": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.2.12.tgz", + "integrity": "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==", + "dependencies": { + "@ai-sdk/provider-utils": "2.2.8", + "@ai-sdk/ui-utils": "1.2.11", + "swr": "^2.2.5", + "throttleit": "2.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/react/node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/react/node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@ai-sdk/ui-utils": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.2.11.tgz", + "integrity": "sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@ai-sdk/ui-utils/node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/ui-utils/node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/bun": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.3.10.tgz", + "integrity": "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ==", + "dev": true, + "dependencies": { + "bun-types": "1.3.10" + } + }, + "node_modules/@types/diff-match-patch": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", + "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "dev": true, + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ai": { + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/ai/-/ai-4.3.19.tgz", + "integrity": "sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8", + "@ai-sdk/react": "1.2.12", + "@ai-sdk/ui-utils": "1.2.11", + "@opentelemetry/api": "1.9.0", + "jsondiffpatch": "0.6.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/ai/node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ai/node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/bun-types": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.3.10.tgz", + "integrity": "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/bundle-require": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "dev": true, + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" + }, + "node_modules/esbuild": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "engines": { + "node": ">=18.0.0" + } + }, + "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, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/jsondiffpatch": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz", + "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==", + "dependencies": { + "@types/diff-match-patch": "^1.0.36", + "chalk": "^5.3.0", + "diff-match-patch": "^1.0.5" + }, + "bin": { + "jsondiffpatch": "bin/jsondiffpatch.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mlly": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.1.tgz", + "integrity": "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==", + "dev": true, + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/swr": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.1.tgz", + "integrity": "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/tsup": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", + "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "dev": true, + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.27.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "^0.7.6", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + } + } +} diff --git a/packages/ai-engine/package.json b/packages/ai-engine/package.json index 000ef77..5cf61e6 100644 --- a/packages/ai-engine/package.json +++ b/packages/ai-engine/package.json @@ -11,12 +11,13 @@ "test": "bun test" }, "dependencies": { - "ai": "^4.0.0", "@ai-sdk/openai-compatible": "^0.1.0", + "ai": "^4.0.0", "zod": "^3.23.0" }, "devDependencies": { "@types/bun": "latest", + "tsup": "^8.5.1", "typescript": "^5.0.0" } } diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..9ecd4b0 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: "./test-suite/e2e", + timeout: 30_000, + fullyParallel: false, + retries: 0, + workers: 1, + use: { + baseURL: "http://127.0.0.1:4173", + channel: "msedge", + headless: true, + }, + webServer: { + command: "npm run preview -- --host 127.0.0.1 --port 4173", + url: "http://127.0.0.1:4173/editor-harness.html", + reuseExistingServer: false, + timeout: 120_000, + }, +}); diff --git a/scripts/build-ai-engine.mjs b/scripts/build-ai-engine.mjs index d93e9e9..c39474d 100644 --- a/scripts/build-ai-engine.mjs +++ b/scripts/build-ai-engine.mjs @@ -1,6 +1,7 @@ import { execSync } from "node:child_process"; -import { mkdirSync } from "node:fs"; +import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import path from "node:path"; +import { pathToFileURL } from "node:url"; function readHostTargetTriple() { const raw = execSync("rustc -vV", { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }); @@ -16,7 +17,6 @@ function resolveTargetTriple() { function run(command, args, options = {}) { const cmd = [command, ...args].join(" "); - // eslint-disable-next-line no-console console.log(`[ai-engine] ${cmd}`); execSync(cmd, { stdio: "inherit", ...options }); } @@ -28,13 +28,43 @@ if (!target) { const exeSuffix = target.includes("windows") ? ".exe" : ""; const outPath = path.join("src-tauri", "bin", `ai-engine-${target}${exeSuffix}`); +const scriptOutPath = path.join("src-tauri", "bin", "ai-engine.js"); +const localReleaseScriptOutPath = path.join("src-tauri", "target", "release", "ai-engine.js"); +const aiEngineDir = path.join("packages", "ai-engine"); +const builtCliPath = path.join(aiEngineDir, "dist", "cli.js"); mkdirSync(path.dirname(outPath), { recursive: true }); +mkdirSync(path.join(aiEngineDir, "dist"), { recursive: true }); -run("bun", ["install", "--frozen-lockfile"], { cwd: path.join("packages", "ai-engine") }); -run( - "bun", - ["build", "src/cli.ts", "--compile", "--outfile", path.resolve(outPath)], - { cwd: path.join("packages", "ai-engine") }, -); +run("npm", ["install", "--no-package-lock"], { cwd: aiEngineDir }); +const esbuildModulePath = pathToFileURL( + path.resolve(aiEngineDir, "node_modules", "esbuild", "lib", "main.js"), +).href; +const { build } = await import(esbuildModulePath); + +console.log("[ai-engine] bundle cli with esbuild"); +await build({ + entryPoints: [path.resolve(aiEngineDir, "src", "cli.ts")], + outfile: path.resolve(builtCliPath), + bundle: true, + platform: "node", + format: "esm", + target: "node18", + minify: true, + sourcemap: false, + legalComments: "none", + packages: "bundle", +}); + +const normalizedCli = readFileSync(builtCliPath, "utf8").replace(/^#!.*\r?\n/, ""); +writeFileSync(builtCliPath, normalizedCli); + +console.log(`[ai-engine] copy ${builtCliPath} -> ${outPath}`); +copyFileSync(builtCliPath, outPath); +console.log(`[ai-engine] copy ${builtCliPath} -> ${scriptOutPath}`); +copyFileSync(builtCliPath, scriptOutPath); +if (existsSync(path.join("src-tauri", "target", "release"))) { + console.log(`[ai-engine] copy ${builtCliPath} -> ${localReleaseScriptOutPath}`); + copyFileSync(builtCliPath, localReleaseScriptOutPath); +} diff --git a/scripts/copy-release-artifacts.mjs b/scripts/copy-release-artifacts.mjs new file mode 100644 index 0000000..cce45d9 --- /dev/null +++ b/scripts/copy-release-artifacts.mjs @@ -0,0 +1,28 @@ +import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync } from "node:fs"; +import path from "node:path"; + +const root = process.cwd(); +const releaseDir = path.join(root, "release"); +const bundleDirs = [ + path.join(root, "src-tauri", "target", "release", "bundle", "msi"), + path.join(root, "src-tauri", "target", "release", "bundle", "nsis"), +]; + +mkdirSync(releaseDir, { recursive: true }); + +for (const name of readdirSync(releaseDir)) { + if (/^CreatorAI_.*\.(msi|exe)$/.test(name)) { + rmSync(path.join(releaseDir, name), { force: true }); + } +} + +for (const dir of bundleDirs) { + if (!existsSync(dir)) continue; + for (const name of readdirSync(dir)) { + if (!/^CreatorAI_.*\.(msi|exe)$/.test(name)) continue; + const from = path.join(dir, name); + const to = path.join(releaseDir, name); + console.log(`[release-copy] ${from} -> ${to}`); + copyFileSync(from, to); + } +} diff --git a/src-tauri/.cargo/config.toml b/src-tauri/.cargo/config.toml new file mode 100644 index 0000000..fe541ae --- /dev/null +++ b/src-tauri/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.'cfg(target_os = "macos")'] +rustflags = ["-C", "link-arg=-mmacosx-version-min=13.4"] \ No newline at end of file diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 360fe37..83d8cff 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -90,6 +90,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -128,6 +178,24 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "ashpd" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093" +dependencies = [ + "async-fs 2.2.0", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.8.5", + "serde", + "serde_repr", + "url", + "zbus 4.4.0", +] + [[package]] name = "async-broadcast" version = "0.5.1" @@ -188,6 +256,17 @@ dependencies = [ "futures-lite 1.13.0", ] +[[package]] +name = "async-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" +dependencies = [ + "async-lock 3.4.2", + "blocking", + "futures-lite 2.6.1", +] + [[package]] name = "async-io" version = "1.13.0" @@ -246,6 +325,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io 2.6.0", + "blocking", + "futures-lite 2.6.1", +] + [[package]] name = "async-process" version = "1.8.1" @@ -468,6 +558,12 @@ dependencies = [ "core2", ] +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.10.4" @@ -698,6 +794,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.43" @@ -720,12 +822,58 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + [[package]] name = "color_quant" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -868,19 +1016,26 @@ dependencies = [ [[package]] name = "creatorai-v2" -version = "0.1.12" +version = "0.1.15" dependencies = [ + "anyhow", "bincode", + "core-foundation 0.9.4", "dirs 5.0.1", "fastembed", "keyring", + "ort", "regex", + "rfd 0.14.1", "serde", "serde_json", + "sha2", "tauri", "tauri-build", "tauri-plugin-dialog", + "tauri-plugin-fs", "tauri-plugin-opener", + "tokenizers 0.15.2", "uuid", ] @@ -971,6 +1126,16 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.11" @@ -991,6 +1156,20 @@ dependencies = [ "darling_macro 0.21.3", ] +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + [[package]] name = "darling_core" version = "0.20.11" @@ -1001,7 +1180,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.114", ] @@ -1015,10 +1194,21 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.114", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.11" @@ -1081,13 +1271,34 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro 0.12.0", +] + [[package]] name = "derive_builder" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ - "derive_builder_macro", + "derive_builder_macro 0.20.2", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -1102,13 +1313,23 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core 0.12.0", + "syn 1.0.109", +] + [[package]] name = "derive_builder_macro" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ - "derive_builder_core", + "derive_builder_core 0.20.2", "syn 2.0.114", ] @@ -1386,6 +1607,9 @@ name = "esaxx-rs" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" +dependencies = [ + "cc", +] [[package]] name = "event-listener" @@ -1442,9 +1666,9 @@ dependencies = [ [[package]] name = "fastembed" -version = "5.8.1" +version = "5.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a3f841f27a44bcc32214f8df75cc9b6cea55dbbebbfe546735690eab5bb2d2" +checksum = "b609359080bf7dfff6ac5ace3d6944355ede4c8a51406a316202ae86ff8346a8" dependencies = [ "anyhow", "hf-hub", @@ -1454,7 +1678,7 @@ dependencies = [ "safetensors", "serde", "serde_json", - "tokenizers", + "tokenizers 0.22.2", ] [[package]] @@ -2568,6 +2792,30 @@ dependencies = [ "once_cell", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2739,7 +2987,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading", + "libloading 0.7.4", "once_cell", ] @@ -2769,6 +3017,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + [[package]] name = "libredox" version = "0.1.12" @@ -2865,6 +3123,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "markup5ever" version = "0.14.1" @@ -3106,6 +3373,19 @@ dependencies = [ "memoffset 0.7.1", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.10.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset 0.9.1", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -3255,6 +3535,26 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + [[package]] name = "objc2" version = "0.6.3" @@ -3467,12 +3767,27 @@ dependencies = [ "objc2-security", ] +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "onig" version = "6.5.1" @@ -3573,6 +3888,7 @@ version = "2.0.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5df903c0d2c07b56950f1058104ab0c8557159f2741782223704de9be73c3c" dependencies = [ + "libloading 0.9.0", "ndarray", "ort-sys", "smallvec", @@ -3910,6 +4226,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "portable-atomic" version = "1.13.1" @@ -4216,7 +4538,7 @@ dependencies = [ "built", "cfg-if", "interpolate_name", - "itertools", + "itertools 0.14.0", "libc", "libfuzzer-sys", "log", @@ -4272,6 +4594,17 @@ dependencies = [ "rayon-core", ] +[[package]] +name = "rayon-cond" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059f538b55efd2309c9794130bc149c6a553db90e9d99c2030785c82f0bd7df9" +dependencies = [ + "either", + "itertools 0.11.0", + "rayon", +] + [[package]] name = "rayon-cond" version = "0.4.0" @@ -4279,7 +4612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f" dependencies = [ "either", - "itertools", + "itertools 0.14.0", "rayon", ] @@ -4450,6 +4783,29 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfd" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" +dependencies = [ + "ashpd", + "block", + "dispatch", + "js-sys", + "log", + "objc", + "objc-foundation", + "objc_id", + "pollster", + "raw-window-handle", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rfd" version = "0.16.0" @@ -5121,6 +5477,12 @@ dependencies = [ "quote", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" @@ -5416,7 +5778,7 @@ checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b" dependencies = [ "log", "raw-window-handle", - "rfd", + "rfd 0.16.0", "serde", "serde_json", "tauri", @@ -5690,6 +6052,39 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tokenizers" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dd47962b0ba36e7fd33518fbf1754d136fd1474000162bbf2a8b5fcb2d3654d" +dependencies = [ + "aho-corasick", + "clap", + "derive_builder 0.12.0", + "esaxx-rs", + "getrandom 0.2.17", + "indicatif", + "itertools 0.12.1", + "lazy_static", + "log", + "macro_rules_attribute", + "monostate", + "onig", + "paste", + "rand 0.8.5", + "rayon", + "rayon-cond 0.3.0", + "regex", + "regex-syntax", + "serde", + "serde_json", + "spm_precompiled", + "thiserror 1.0.69", + "unicode-normalization-alignments", + "unicode-segmentation", + "unicode_categories", +] + [[package]] name = "tokenizers" version = "0.22.2" @@ -5700,10 +6095,10 @@ dependencies = [ "aho-corasick", "compact_str", "dary_heap", - "derive_builder", + "derive_builder 0.20.2", "esaxx-rs", "getrandom 0.3.4", - "itertools", + "itertools 0.14.0", "log", "macro_rules_attribute", "monostate", @@ -5711,7 +6106,7 @@ dependencies = [ "paste", "rand 0.9.2", "rayon", - "rayon-cond", + "rayon-cond 0.4.0", "regex", "regex-syntax", "serde", @@ -6136,6 +6531,12 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "urlpattern" version = "0.3.0" @@ -6160,6 +6561,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.20.0" @@ -7136,7 +7543,7 @@ checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" dependencies = [ "async-broadcast 0.5.1", "async-executor", - "async-fs", + "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", "async-process 1.8.1", @@ -7152,7 +7559,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix", + "nix 0.26.4", "once_cell", "ordered-stream", "rand 0.8.5", @@ -7169,6 +7576,44 @@ dependencies = [ "zvariant 3.15.2", ] +[[package]] +name = "zbus" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" +dependencies = [ + "async-broadcast 0.7.2", + "async-executor", + "async-fs 2.2.0", + "async-io 2.6.0", + "async-lock 3.4.2", + "async-process 2.5.0", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener 5.4.1", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.29.0", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + [[package]] name = "zbus" version = "5.13.2" @@ -7218,6 +7663,19 @@ dependencies = [ "zvariant_utils 1.0.1", ] +[[package]] +name = "zbus_macros" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", + "zvariant_utils 2.1.0", +] + [[package]] name = "zbus_macros" version = "5.13.2" @@ -7244,6 +7702,17 @@ dependencies = [ "zvariant 3.15.2", ] +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant 4.2.0", +] + [[package]] name = "zbus_names" version = "4.3.1" @@ -7394,6 +7863,20 @@ dependencies = [ "zvariant_derive 3.15.2", ] +[[package]] +name = "zvariant" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "zvariant_derive 4.2.0", +] + [[package]] name = "zvariant" version = "5.9.2" @@ -7421,6 +7904,19 @@ dependencies = [ "zvariant_utils 1.0.1", ] +[[package]] +name = "zvariant_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", + "zvariant_utils 2.1.0", +] + [[package]] name = "zvariant_derive" version = "5.9.2" @@ -7445,6 +7941,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "zvariant_utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "zvariant_utils" version = "3.3.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ff93b06..c648ee1 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,31 +1,55 @@ [package] name = "creatorai-v2" -version = "0.1.12" +version = "0.1.15" description = "A Tauri App" authors = ["you"] +license = "" +repository = "" +default-run = "creatorai-v2" edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +rust-version = "1.77" [lib] -# The `_lib` suffix may seem redundant but it is necessary -# to make the lib name unique and wouldn't conflict with the bin name. -# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 name = "creatorai_v2_lib" -crate-type = ["staticlib", "cdylib", "rlib"] +crate-type = ["lib", "cdylib", "staticlib"] [build-dependencies] -tauri-build = { version = "2", features = [] } +tauri-build = { version = "2.0.0-rc", features = [] } [dependencies] -tauri = { version = "2.10", features = [] } -tauri-plugin-dialog = "2" -tauri-plugin-opener = "2" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -bincode = "1" -dirs = "5" -fastembed = "5" -keyring = "2" -regex = "1" -uuid = { version = "1", features = ["v4", "serde"] } +tauri = { version = "2.0.0-rc", features = ["tray-icon"] } +tauri-plugin-opener = { version = "2.0.0-rc" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tauri-plugin-fs = "2.0.0-rc" +rfd = "0.14.1" +dirs = "5.0.1" +fastembed = "5.12.1" +ort = { version = "=2.0.0-rc.11", features = ["load-dynamic", "cuda", "copy-dylibs"] } +tokenizers = "=0.15.2" +anyhow = "1.0.86" +tauri-plugin-dialog = "2.0.0-rc" +regex = "1.10.4" +keyring = "2.3.3" +bincode = "1.3.3" +uuid = { version = "1.0.0", features = ["v4", "serde"] } +sha2 = "0.10.9" + +[target.'cfg(target_os = "macos")'.dependencies] +tauri = { version = "2.0.0-rc", features = ["tray-icon"] } +core-foundation = "0.9" + +[package.metadata.bundle] +category = "public.app-category.developer-tools" + +[profile.dev] +incremental = true + +[profile.release] +codegen-units = 1 +lto = true +panic = "abort" +strip = true + +# 添加 macOS 链接配置 +[target.'cfg(target_os = "macos")'.build-dependencies] diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 324fee1..5c48ce1 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -1,12 +1,33 @@ +use std::process::Command; +use std::path::PathBuf; + fn main() { + // Ensure AI engine sidecar is available ensure_ai_engine_sidecar(); - tauri_build::build() + + // Set minimum macOS version requirement for MLComputePlan symbol + if cfg!(target_os = "macos") { + println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=13.3"); + println!("cargo:rustc-link-arg=-mmacosx-version-min=13.3"); + + // Additional linker args for Apple Silicon + if cfg!(target_arch = "aarch64") { + println!("cargo:rustc-link-arg=-stdlib=libc++"); + } + + // Link required frameworks + println!("cargo:rustc-link-lib=framework=Metal"); + println!("cargo:rustc-link-lib=framework=CoreML"); + println!("cargo:rustc-link-lib=framework=Foundation"); + + // Add weak linking for MLCompute framework to resolve MLComputePlan symbol issues + println!("cargo:rustc-link-arg=-Wl,-weak_framework,MLCompute"); + } + + tauri_build::build(); } fn ensure_ai_engine_sidecar() { - use std::path::PathBuf; - use std::process::Command; - let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap_or_default()); let target = std::env::var("TARGET").unwrap_or_default(); if manifest_dir.as_os_str().is_empty() || target.trim().is_empty() { diff --git a/src-tauri/src/ai_bridge.rs b/src-tauri/src/ai_bridge.rs index eabdbb1..795aa07 100644 --- a/src-tauri/src/ai_bridge.rs +++ b/src-tauri/src/ai_bridge.rs @@ -81,9 +81,13 @@ fn current_exe_dir() -> Option { fn find_ai_engine_in_dir(dir: &Path) -> Option { let direct_names = if cfg!(windows) { - vec!["ai-engine.exe".to_string(), "ai-engine".to_string()] + vec![ + "ai-engine.js".to_string(), + "ai-engine.exe".to_string(), + "ai-engine".to_string(), + ] } else { - vec!["ai-engine".to_string()] + vec!["ai-engine.js".to_string(), "ai-engine".to_string()] }; for name in direct_names { @@ -110,6 +114,7 @@ fn find_ai_engine_in_dir(dir: &Path) -> Option { fn find_bundled_ai_engine() -> Option { let exe_dir = current_exe_dir()?; let candidates = [ + exe_dir.join("bin"), exe_dir.clone(), exe_dir.join("../Resources"), exe_dir.join("../Resources/bin"), @@ -187,8 +192,16 @@ fn is_script_path(path: &Path) -> bool { fn spawn_ai_engine(path: &Path) -> Result { let mut cmd = if is_script_path(path) { - let mut c = Command::new("bun"); - c.arg("run").arg(path); + let extension = path.extension().and_then(|s| s.to_str()).unwrap_or_default(); + let mut c = if extension == "js" { + let mut node = Command::new("node"); + node.arg(path); + node + } else { + let mut bun = Command::new("bun"); + bun.arg("run").arg(path); + bun + }; // For script execution, keep a stable cwd (prefer repo root when available). if let Some(root) = dev_repo_root_dir().filter(|p| p.exists()) { @@ -203,13 +216,27 @@ fn spawn_ai_engine(path: &Path) -> Result { cmd.stdin(Stdio::piped()) .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) + .stderr(Stdio::inherit()); + + #[cfg(windows)] + { + use std::os::windows::process::CommandExt; + const CREATE_NO_WINDOW: u32 = 0x0800_0000; + cmd.creation_flags(CREATE_NO_WINDOW); + } + + cmd .spawn() .map_err(|e| { if is_script_path(path) && matches!(e.kind(), std::io::ErrorKind::NotFound) { + let runtime = if path.extension().and_then(|s| s.to_str()) == Some("js") { + "node" + } else { + "bun" + }; return format!( - "Failed to spawn ai-engine: {e}. `bun` is required to run `{}`. Install Bun or build the bundled sidecar via `npm run ai-engine:build`.", - path.display() + "Failed to spawn ai-engine: {e}. `{runtime}` is required to run `{}`. Install the runtime or build the bundled sidecar via `npm run ai-engine:build`.", + path.display(), ); } format!("Failed to spawn ai-engine: {e}") @@ -964,10 +991,28 @@ mod tests { fs::write(root.join("chapters/index.json"), format!("{json}\n")).unwrap(); } - const MOCK_AI_ENGINE_CLI: &str = r#"#!/usr/bin/env bun -const stdinReader = Bun.stdin.stream().getReader(); -const decoder = new TextDecoder(); + const MOCK_AI_ENGINE_CLI: &str = r#"#!/usr/bin/env node let stdinBuffer = ""; +let stdinEnded = false; +let wakeReader = null; + +process.stdin.setEncoding("utf8"); +process.stdin.on("data", (chunk) => { + stdinBuffer += chunk; + if (wakeReader) { + const resolve = wakeReader; + wakeReader = null; + resolve(); + } +}); +process.stdin.on("end", () => { + stdinEnded = true; + if (wakeReader) { + const resolve = wakeReader; + wakeReader = null; + resolve(); + } +}); async function readJsonFromStdin() { while (true) { @@ -979,11 +1024,12 @@ async function readJsonFromStdin() { return JSON.parse(line); } - const { done, value } = await stdinReader.read(); - if (done) { + if (stdinEnded) { throw new Error("EOF before complete JSON"); } - stdinBuffer += decoder.decode(value, { stream: true }); + await new Promise((resolve) => { + wakeReader = resolve; + }); } } @@ -1096,7 +1142,7 @@ main().catch((err) => { fn ensure_mock_ai_engine_cli() { static PATH: OnceLock = OnceLock::new(); let path = PATH.get_or_init(|| { - let p = std::env::temp_dir().join("creatorai-v2-mock-ai-engine-cli.ts"); + let p = std::env::temp_dir().join("creatorai-v2-mock-ai-engine-cli.js"); if let Ok(existing) = fs::read_to_string(&p) { if existing == MOCK_AI_ENGINE_CLI { return p; @@ -1289,4 +1335,57 @@ main().catch((err) => { let after = fs::read_to_string(temp.path.join("chapters/chapter_003.txt")).unwrap(); assert_eq!(after, "hello\n"); } + + #[test] + fn finds_ai_engine_in_installed_bin_directory() { + let temp = TempDir::new("creatorai-v2-ai-engine-installed-layout"); + let install_dir = temp.path.join("CreatorAI"); + let bin_dir = install_dir.join("bin"); + fs::create_dir_all(&bin_dir).unwrap(); + let engine_path = bin_dir.join(if cfg!(windows) { + "ai-engine.js" + } else { + "ai-engine" + }); + fs::write(&engine_path, "test").unwrap(); + + let found = find_ai_engine_in_dir(&bin_dir).expect("should find engine in bin dir"); + assert_eq!(found, engine_path); + } + + #[test] + fn bundled_lookup_prefers_installed_bin_over_root_fake_exe() { + let temp = TempDir::new("creatorai-v2-ai-engine-installed-priority"); + let install_dir = temp.path.join("CreatorAI"); + let bin_dir = install_dir.join("bin"); + fs::create_dir_all(&bin_dir).unwrap(); + + let root_fake_exe = install_dir.join(if cfg!(windows) { + "ai-engine.exe" + } else { + "ai-engine" + }); + fs::write(&root_fake_exe, "fake").unwrap(); + + let bin_js = bin_dir.join("ai-engine.js"); + fs::write(&bin_js, "real").unwrap(); + + let found_root = find_ai_engine_in_dir(&install_dir).expect("should find root engine"); + assert_eq!(found_root, root_fake_exe); + + let candidates = [ + install_dir.join("bin"), + install_dir.clone(), + install_dir.join("../Resources"), + install_dir.join("../Resources/bin"), + install_dir.join("../MacOS"), + install_dir.join("../bin"), + ]; + + let found = candidates + .iter() + .find_map(|dir| find_ai_engine_in_dir(dir)) + .expect("should find installed sidecar"); + assert_eq!(found, bin_js); + } } diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs index ceb0419..da01d7a 100644 --- a/src-tauri/src/config.rs +++ b/src-tauri/src/config.rs @@ -3,6 +3,12 @@ use std::collections::HashMap; use std::fs; use std::path::PathBuf; +const LEGACY_GLM_DEMO_PROVIDER_ID: &str = "builtin_glm_4_7_demo"; +const BUILTIN_DEMO_PROVIDER_ID: &str = "builtin_dashscope_qwen_demo"; +const BUILTIN_DEMO_PROVIDER_NAME: &str = "DashScope Qwen Demo"; +const BUILTIN_DEMO_BASE_URL: &str = "https://dashscope.aliyuncs.com/compatible-mode/v1"; +const BUILTIN_DEMO_MODEL: &str = "qwen-plus"; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GlobalConfig { pub schema_version: u32, @@ -42,19 +48,21 @@ pub struct ModelParameters { impl Default for GlobalConfig { fn default() -> Self { - Self { + let mut config = Self { schema_version: 1, providers: vec![], active_provider_id: None, default_parameters: ModelParameters::default(), - } + }; + ensure_builtin_demo_provider(&mut config, false); + config } } impl Default for ModelParameters { fn default() -> Self { Self { - model: String::new(), + model: BUILTIN_DEMO_MODEL.to_string(), temperature: 0.7, top_p: 1.0, top_k: None, @@ -63,6 +71,112 @@ impl Default for ModelParameters { } } +fn builtin_demo_provider() -> Provider { + Provider { + id: BUILTIN_DEMO_PROVIDER_ID.to_string(), + name: BUILTIN_DEMO_PROVIDER_NAME.to_string(), + base_url: BUILTIN_DEMO_BASE_URL.to_string(), + models: vec![BUILTIN_DEMO_MODEL.to_string()], + models_updated_at: None, + provider_type: ProviderType::OpenaiCompatible, + headers: None, + } +} + +fn normalize_builtin_demo_provider(provider: &mut Provider) -> bool { + let canonical = builtin_demo_provider(); + let mut changed = false; + + if provider.name != canonical.name { + provider.name = canonical.name; + changed = true; + } + if provider.base_url != canonical.base_url { + provider.base_url = canonical.base_url; + changed = true; + } + if provider.models != canonical.models { + provider.models = canonical.models; + changed = true; + } + if provider.models_updated_at.is_some() { + provider.models_updated_at = None; + changed = true; + } + if !matches!(provider.provider_type, ProviderType::OpenaiCompatible) { + provider.provider_type = ProviderType::OpenaiCompatible; + changed = true; + } + if provider.headers.is_some() { + provider.headers = None; + changed = true; + } + + changed +} + +fn is_legacy_glm_provider(provider: &Provider) -> bool { + provider.id == LEGACY_GLM_DEMO_PROVIDER_ID + || provider + .base_url + .contains("open.bigmodel.cn/api/paas/v4") + || provider.name.trim().eq_ignore_ascii_case("glm-4.7") +} + +fn ensure_builtin_demo_provider(config: &mut GlobalConfig, cleanup_keyring: bool) -> bool { + let mut changed = false; + + let legacy_active_provider_id = config.active_provider_id.clone().filter(|id| { + config + .providers + .iter() + .any(|provider| provider.id == *id && is_legacy_glm_provider(provider)) + }); + + let before_len = config.providers.len(); + config + .providers + .retain(|provider| !is_legacy_glm_provider(provider)); + if config.providers.len() != before_len { + changed = true; + } + + if let Some(provider) = config + .providers + .iter_mut() + .find(|provider| provider.id == BUILTIN_DEMO_PROVIDER_ID) + { + if normalize_builtin_demo_provider(provider) { + changed = true; + } + } else { + config.providers.insert(0, builtin_demo_provider()); + changed = true; + } + + if config.active_provider_id.is_none() + || config.active_provider_id.as_deref() == Some(LEGACY_GLM_DEMO_PROVIDER_ID) + || legacy_active_provider_id.is_some() + { + config.active_provider_id = Some(BUILTIN_DEMO_PROVIDER_ID.to_string()); + changed = true; + } + + if config.default_parameters.model.trim().is_empty() + || config.default_parameters.model.trim() == "glm-4.7" + { + config.default_parameters.model = BUILTIN_DEMO_MODEL.to_string(); + changed = true; + } + + if cleanup_keyring { + let _ = crate::keyring_store::delete_api_key(LEGACY_GLM_DEMO_PROVIDER_ID); + let _ = crate::keyring_store::purge_leaked_builtin_demo_key(); + } + + changed +} + fn get_config_dir() -> Result { if let Ok(dir) = std::env::var("CREATORAI_CONFIG_DIR") { let config_dir = PathBuf::from(dir); @@ -84,13 +198,27 @@ fn get_config_path() -> Result { Ok(get_config_dir()?.join("config.json")) } +pub fn get_global_config_dir() -> Result { + get_config_dir() +} + pub fn load_config() -> Result { let path = get_config_path()?; - if !path.exists() { - return Ok(GlobalConfig::default()); + let (mut config, loaded_from_disk) = if !path.exists() { + (GlobalConfig::default(), false) + } else { + let content = fs::read_to_string(&path).map_err(|e| e.to_string())?; + let content = content.trim_start_matches('\u{feff}').to_string(); + ( + serde_json::from_str(&content).map_err(|e| e.to_string())?, + true, + ) + }; + let changed = ensure_builtin_demo_provider(&mut config, true); + if loaded_from_disk && changed { + save_config(&config)?; } - let content = fs::read_to_string(&path).map_err(|e| e.to_string())?; - serde_json::from_str(&content).map_err(|e| e.to_string()) + Ok(config) } pub fn save_config(config: &GlobalConfig) -> Result<(), String> { @@ -126,11 +254,98 @@ mod tests { save_config(&config).expect("save_config should succeed"); let loaded = load_config().expect("load_config should succeed"); - assert_eq!(loaded.providers.len(), 1); - assert_eq!(loaded.providers[0].id, "test"); + assert!(loaded.providers.iter().any(|provider| provider.id == "test")); + assert!(loaded + .providers + .iter() + .any(|provider| provider.id == BUILTIN_DEMO_PROVIDER_ID)); let _ = fs::remove_dir_all(&tmp_dir); std::env::remove_var("CREATORAI_CONFIG_DIR"); } + + #[test] + fn default_config_contains_builtin_dashscope_demo_provider() { + let config = GlobalConfig::default(); + assert_eq!( + config.active_provider_id.as_deref(), + Some(BUILTIN_DEMO_PROVIDER_ID) + ); + assert_eq!(config.default_parameters.model, BUILTIN_DEMO_MODEL); + assert!(config + .providers + .iter() + .any(|provider| provider.id == BUILTIN_DEMO_PROVIDER_ID + && provider.base_url == BUILTIN_DEMO_BASE_URL + && provider.models == vec![BUILTIN_DEMO_MODEL.to_string()])); + } + + #[test] + fn legacy_glm_provider_is_replaced_by_builtin_dashscope_demo() { + let mut config = GlobalConfig { + schema_version: 1, + providers: vec![Provider { + id: "provider_legacy".to_string(), + name: "glm-4.7".to_string(), + base_url: "https://open.bigmodel.cn/api/paas/v4/chat/completions".to_string(), + models: vec![], + models_updated_at: None, + provider_type: ProviderType::Anthropic, + headers: None, + }], + active_provider_id: Some("provider_legacy".to_string()), + default_parameters: ModelParameters { + model: "glm-4.7".to_string(), + temperature: 0.7, + top_p: 1.0, + top_k: None, + max_tokens: 2000, + }, + }; + + let changed = ensure_builtin_demo_provider(&mut config, false); + assert!(changed); + assert_eq!(config.providers.len(), 1); + assert_eq!(config.providers[0].id, BUILTIN_DEMO_PROVIDER_ID); + assert_eq!( + config.active_provider_id.as_deref(), + Some(BUILTIN_DEMO_PROVIDER_ID) + ); + assert_eq!(config.default_parameters.model, BUILTIN_DEMO_MODEL); + } + + #[test] + fn malformed_builtin_provider_is_normalized() { + let mut config = GlobalConfig { + schema_version: 1, + providers: vec![Provider { + id: BUILTIN_DEMO_PROVIDER_ID.to_string(), + name: "Old Demo".to_string(), + base_url: "https://example.com/wrong".to_string(), + models: vec![], + models_updated_at: Some(123), + provider_type: ProviderType::Google, + headers: Some(HashMap::from([( + "x-test".to_string(), + "1".to_string(), + )])), + }], + active_provider_id: Some(BUILTIN_DEMO_PROVIDER_ID.to_string()), + default_parameters: ModelParameters::default(), + }; + + let changed = ensure_builtin_demo_provider(&mut config, false); + assert!(changed); + assert_eq!(config.providers.len(), 1); + assert_eq!(config.providers[0].name, BUILTIN_DEMO_PROVIDER_NAME); + assert_eq!(config.providers[0].base_url, BUILTIN_DEMO_BASE_URL); + assert_eq!(config.providers[0].models, vec![BUILTIN_DEMO_MODEL.to_string()]); + assert!(config.providers[0].models_updated_at.is_none()); + assert!(matches!( + config.providers[0].provider_type, + ProviderType::OpenaiCompatible + )); + assert!(config.providers[0].headers.is_none()); + } } diff --git a/src-tauri/src/keyring_store.rs b/src-tauri/src/keyring_store.rs index fb8eb8b..123f913 100644 --- a/src-tauri/src/keyring_store.rs +++ b/src-tauri/src/keyring_store.rs @@ -1,6 +1,16 @@ use keyring::Entry; +use sha2::{Digest, Sha256}; const SERVICE_NAME: &str = "creatorai"; +const BUILTIN_DEMO_PROVIDER_ID: &str = "builtin_dashscope_qwen_demo"; +const LEAKED_BUILTIN_DEMO_API_KEY_SHA256: &str = + "3a8e03e89c2bfa7d360dea9f57476bac4e922cbcf6a876ae68d662a388331a0e"; + +fn sha256_hex(input: &str) -> String { + let mut hasher = Sha256::new(); + hasher.update(input.as_bytes()); + format!("{:x}", hasher.finalize()) +} pub fn store_api_key(provider_id: &str, api_key: &str) -> Result<(), String> { let entry = Entry::new(SERVICE_NAME, provider_id).map_err(|e| e.to_string())?; @@ -10,6 +20,13 @@ pub fn store_api_key(provider_id: &str, api_key: &str) -> Result<(), String> { pub fn get_api_key(provider_id: &str) -> Result, String> { let entry = Entry::new(SERVICE_NAME, provider_id).map_err(|e| e.to_string())?; match entry.get_password() { + Ok(key) + if provider_id == BUILTIN_DEMO_PROVIDER_ID + && sha256_hex(&key) == LEAKED_BUILTIN_DEMO_API_KEY_SHA256 => + { + let _ = entry.delete_password(); + Ok(None) + } Ok(key) => Ok(Some(key)), Err(keyring::Error::NoEntry) => Ok(None), Err(e) => Err(e.to_string()), @@ -24,3 +41,15 @@ pub fn delete_api_key(provider_id: &str) -> Result<(), String> { Err(e) => Err(e.to_string()), } } + +pub fn purge_leaked_builtin_demo_key() -> Result { + let entry = Entry::new(SERVICE_NAME, BUILTIN_DEMO_PROVIDER_ID).map_err(|e| e.to_string())?; + match entry.get_password() { + Ok(key) if sha256_hex(&key) == LEAKED_BUILTIN_DEMO_API_KEY_SHA256 => { + entry.delete_password().map_err(|e| e.to_string())?; + Ok(true) + } + Ok(_) | Err(keyring::Error::NoEntry) => Ok(false), + Err(e) => Err(e.to_string()), + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b5a5b56..62d1fd4 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -32,11 +32,75 @@ use session::{ add_message, create_session, delete_session, get_session_messages, list_sessions, rename_session, update_message_metadata, compact_session, }; +use std::fs; use std::path::Path; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::time::{SystemTime, UNIX_EPOCH}; +fn clear_dir_if_exists(path: &Path) -> Result<(), String> { + if !path.exists() { + return Ok(()); + } + fs::remove_dir_all(path) + .map_err(|e| format!("Failed to remove '{}': {e}", path.display())) +} + +fn clear_file_if_exists(path: &Path) -> Result<(), String> { + if !path.exists() { + return Ok(()); + } + fs::remove_file(path) + .map_err(|e| format!("Failed to remove '{}': {e}", path.display())) +} + +fn install_cleanup_marker_path() -> Result { + Ok(config::get_global_config_dir()?.join("ui_cleanup_pending")) +} + +fn cleanup_reinstall_state_if_needed() -> Result<(), String> { + if cfg!(debug_assertions) { + return Ok(()); + } + + let config_dir = config::get_global_config_dir()?; + let marker_path = config_dir.join("install_version.txt"); + let current_version = env!("CARGO_PKG_VERSION"); + let previous_version = fs::read_to_string(&marker_path).unwrap_or_default(); + if previous_version.trim() == current_version { + return Ok(()); + } + + clear_file_if_exists(&config_dir.join("recent.json"))?; + + if let Some(roaming) = dirs::data_dir() { + clear_dir_if_exists(&roaming.join("creatorai"))?; + clear_dir_if_exists(&roaming.join("com.link.creatorai-v2"))?; + } + + if let Some(local) = dirs::data_local_dir() { + clear_dir_if_exists(&local.join("com.link.creatorai-v2"))?; + } + + fs::write(install_cleanup_marker_path()?, b"pending\n") + .map_err(|e| format!("Failed to write UI cleanup marker: {e}"))?; + + fs::write(&marker_path, format!("{current_version}\n")) + .map_err(|e| format!("Failed to write install marker: {e}"))?; + Ok(()) +} + +#[tauri::command] +fn consume_ui_cleanup_flag() -> Result { + let marker = install_cleanup_marker_path()?; + if !marker.exists() { + return Ok(false); + } + fs::remove_file(&marker) + .map_err(|e| format!("Failed to remove UI cleanup marker: {e}"))?; + Ok(true) +} + #[tauri::command] fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) @@ -485,6 +549,12 @@ pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_opener::init()) + .setup(|_| { + cleanup_reinstall_state_if_needed()?; + config::load_config() + .map(|_| ()) + .map_err(|error| -> Box { error.into() }) + }) .manage(AiChatRuntime::default()) .manage(AiCompleteRuntime::default()) .invoke_handler(tauri::generate_handler![ @@ -544,6 +614,7 @@ pub fn run() { add_message, update_message_metadata, compact_session, + consume_ui_cleanup_flag, preview_import_txt, import_txt ]) @@ -783,6 +854,54 @@ mod tests { assert_eq!(chapters2[0].order, 1); } + #[test] + fn chapter_save_persists_latest_content_across_multiple_writes() { + let temp = TempDir::new("creatorai-v2-chapter-save"); + let project_root = temp.path.join("MyNovel"); + let project_path = project_root.to_string_lossy().to_string(); + + tauri::async_runtime::block_on(create_project( + project_path.clone(), + "Test Novel".to_string(), + )) + .expect("create_project"); + + let chapter = tauri::async_runtime::block_on(create_chapter( + project_path.clone(), + "Chapter 1".to_string(), + )) + .expect("create_chapter"); + + tauri::async_runtime::block_on(save_chapter_content( + project_path.clone(), + chapter.id.clone(), + "first draft".to_string(), + )) + .expect("save first draft"); + + tauri::async_runtime::block_on(save_chapter_content( + project_path.clone(), + chapter.id.clone(), + "first draft\nsecond line\nfinal paragraph".to_string(), + )) + .expect("save second draft"); + + let reloaded = tauri::async_runtime::block_on(get_chapter_content( + project_path.clone(), + chapter.id.clone(), + )) + .expect("reload chapter content"); + assert_eq!(reloaded, "first draft\nsecond line\nfinal paragraph"); + + let listed = + tauri::async_runtime::block_on(list_chapters(project_path.clone())).expect("list"); + let saved_meta = listed + .iter() + .find(|item| item.id == chapter.id) + .expect("saved chapter metadata"); + assert_eq!(saved_meta.word_count, "first draft\nsecond line\nfinal paragraph".chars().filter(|c| !c.is_whitespace()).count() as u32); + } + #[test] fn session_storage_smoke_test() { use uuid::Uuid; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 365d087..97e7261 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "CreatorAI", - "version": "0.1.12", + "version": "0.1.15", "identifier": "com.creatorai.app", "build": { "beforeDevCommand": "npm run dev", @@ -27,6 +27,9 @@ "externalBin": [ "bin/ai-engine" ], + "resources": [ + "bin/ai-engine.js" + ], "icon": [ "icons/32x32.png", "icons/128x128.png", diff --git a/src/App.tsx b/src/App.tsx index ef704f5..5911f8f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -28,6 +28,13 @@ function joinPath(parent: string, child: string): string { return `${trimmedParent}${separator}${child}`; } +async function tauriInvoke(command: string, args?: Record): Promise { + if (!isTauri()) { + throw new Error("当前为浏览器模式,文件系统能力不可用。请使用 npm run tauri:dev 并在桌面窗口中操作。"); + } + return invoke(command, args); +} + export default function App() { const { theme, toggle } = useTheme(); const [currentProject, setCurrentProject] = useState<{ path: string; config: ProjectConfig } | null>( @@ -39,8 +46,12 @@ export default function App() { const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const loadRecentProjects = async () => { + if (!isTauri()) { + setRecentProjects([]); + return; + } try { - const recent = (await invoke("get_recent_projects")) as RecentProject[]; + const recent = await tauriInvoke("get_recent_projects"); setRecentProjects(recent || []); } catch { setRecentProjects([]); @@ -51,6 +62,33 @@ export default function App() { void loadRecentProjects(); }, []); + useEffect(() => { + if (!isTauri()) return; + + const clearUiStateIfNeeded = async () => { + try { + const shouldClear = await tauriInvoke("consume_ui_cleanup_flag"); + if (!shouldClear) return; + + const keysToRemove: string[] = []; + for (let i = 0; i < localStorage.length; i += 1) { + const key = localStorage.key(i); + if (key && key.startsWith("creatorai:")) { + keysToRemove.push(key); + } + } + for (const key of keysToRemove) { + localStorage.removeItem(key); + } + sessionStorage.clear(); + } catch { + // ignore cleanup failures to avoid blocking app startup + } + }; + + void clearUiStateIfNeeded(); + }, []); + useEffect(() => { const onUnhandledRejection = (event: PromiseRejectionEvent) => { // eslint-disable-next-line no-console @@ -87,7 +125,17 @@ export default function App() { useEffect(() => { if (!currentProject) return; - if (!isTauri()) return; + + // 安全地检测是否在 Tauri 环境中 + let isTauriEnv = false; + try { + isTauriEnv = isTauri(); + } catch (error) { + // 在浏览器环境中,isTauri() 可能会抛出错误 + isTauriEnv = false; + } + + if (!isTauriEnv) return; let unlisten: (() => void) | null = null; const setup = async () => { @@ -113,7 +161,16 @@ export default function App() { const confirmDiscardUnsaved = async (actionText: string) => { if (!hasUnsavedChanges) return true; - if (isTauri()) { + + // 安全地检测是否在 Tauri 环境中 + let isTauriEnv = false; + try { + isTauriEnv = isTauri(); + } catch (error) { + isTauriEnv = false; + } + + if (isTauriEnv) { return confirm(`当前章节有未保存的更改,${actionText}将丢失这些更改。是否继续?`, { title: "未保存更改", kind: "warning", @@ -130,10 +187,10 @@ export default function App() { setProjectBusy(true); message.loading({ content: "正在打开项目...", key: "project" }); try { - const config = (await invoke("open_project", { path })) as ProjectConfig; + const config = await tauriInvoke("open_project", { path }); setCurrentProject({ path, config }); setHasUnsavedChanges(false); - await invoke("add_recent_project", { name: config.name, path }); + await tauriInvoke("add_recent_project", { name: config.name, path }); await loadRecentProjects(); message.success({ content: `已打开项目:${config.name}`, key: "project" }); } catch (error) { @@ -145,13 +202,29 @@ export default function App() { const handleOpenProjectDialog = async () => { try { - const selected = await open({ - directory: true, - multiple: false, - title: "选择项目文件夹", - }); - if (typeof selected === "string" && selected.trim()) { - await openProject(selected); + // 安全地检测是否在 Tauri 环境中 + let isTauriEnv = false; + try { + isTauriEnv = isTauri(); + } catch (error) { + isTauriEnv = false; + } + + if (isTauriEnv) { + const selected = await open({ + directory: true, + multiple: false, + title: "选择项目文件夹", + }); + if (typeof selected === "string" && selected.trim()) { + await openProject(selected); + } + } else { + // 在浏览器环境中,提示用户手动输入路径 + const userInput = prompt("当前为 Web 环境,请手动输入项目文件夹路径:"); + if (userInput && userInput.trim()) { + await openProject(userInput.trim()); + } } } catch (error) { message.error(`打开失败: ${formatError(error)}`); @@ -171,13 +244,13 @@ export default function App() { setProjectBusy(true); message.loading({ content: "正在创建项目...", key: "project" }); try { - const config = (await invoke("create_project", { + const config = await tauriInvoke("create_project", { path: projectPath, name: trimmedName, - })) as ProjectConfig; + }); setCurrentProject({ path: projectPath, config }); setHasUnsavedChanges(false); - await invoke("add_recent_project", { name: config.name, path: projectPath }); + await tauriInvoke("add_recent_project", { name: config.name, path: projectPath }); await loadRecentProjects(); setCreateProjectModalOpen(false); message.success({ content: `项目已创建:${config.name}`, key: "project" }); diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx index f77dfe2..627b45f 100644 --- a/src/components/Editor/Editor.tsx +++ b/src/components/Editor/Editor.tsx @@ -1,6 +1,6 @@ import { Empty, message } from "antd"; import { invoke } from "@tauri-apps/api/core"; -import { EditorState, type Extension } from "@codemirror/state"; +import { EditorSelection, EditorState, type Extension } from "@codemirror/state"; import { EditorView, keymap } from "@codemirror/view"; import { history, historyKeymap, indentWithTab, redo, redoDepth, undo, undoDepth } from "@codemirror/commands"; import { @@ -40,16 +40,26 @@ export interface EditorProps { chapterId: string | null; chapterTitle: string; initialContent: string; + disableInlineCompletion?: boolean; onChange: (content: string) => void; onSave: (content: string) => Promise; onSaveStatusChange?: (status: SaveStatus) => void; } +const saveErrorMessage = "保存失败,请稍后重试。"; + +function runSaveShortcut(save: () => Promise) { + void save().catch(() => { + message.error(saveErrorMessage); + }); +} + function Editor({ projectPath, chapterId, chapterTitle, initialContent, + disableInlineCompletion = false, onChange, onSave, onSaveStatusChange, @@ -141,9 +151,11 @@ function Editor({ const selection = view.state.selection.main; if (!selection.empty) return; - completionTimerRef.current = window.setTimeout(() => { - void requestCompletion(view); - }, 700); + if (!disableInlineCompletion) { + completionTimerRef.current = window.setTimeout(() => { + void requestCompletion(view); + }, 700); + } }; const requestCompletion = async (view: EditorView) => { @@ -201,6 +213,32 @@ function Editor({ inlineCompletionField, inlineCompletionTheme, keymap.of([ + { + key: "Mod-z", + run: undo, + preventDefault: true, + }, + { + key: "Mod-Shift-z", + run: redo, + preventDefault: true, + }, + { + win: "Ctrl-y", + linux: "Ctrl-y", + run: redo, + preventDefault: true, + }, + { + key: "Mod-a", + run: (view) => { + view.dispatch({ + selection: EditorSelection.single(0, view.state.doc.length), + }); + return true; + }, + preventDefault: true, + }, { key: "Tab", run: (view) => { @@ -229,6 +267,14 @@ function Editor({ return true; }, }, + { + win: "Ctrl-Shift-s", + linux: "Ctrl-Shift-s", + run: () => { + runSaveShortcut(saveRef.current); + return true; + }, + }, ...historyKeymap, ]), EditorView.updateListener.of((update) => { @@ -302,7 +348,7 @@ function Editor({ view.destroy(); viewRef.current = null; }; - }, [chapterId, projectPath]); + }, [chapterId, projectPath, disableInlineCompletion]); useEffect(() => { if (!chapterId) return; diff --git a/src/components/Editor/EditorHeader.tsx b/src/components/Editor/EditorHeader.tsx index 3ea5dcf..68a89a3 100644 --- a/src/components/Editor/EditorHeader.tsx +++ b/src/components/Editor/EditorHeader.tsx @@ -25,7 +25,7 @@ export default function EditorHeader({