diff --git a/TODO/done/14-conversation-rendering-hierarchy.md b/TODO/done/14-conversation-rendering-hierarchy.md new file mode 100644 index 0000000..47ae9ec --- /dev/null +++ b/TODO/done/14-conversation-rendering-hierarchy.md @@ -0,0 +1,126 @@ +# POST-MVP-04:对话渲染层级与实时回答 + +- 状态:已完成 +- 优先级:P0 +- 前置任务:MVP-04 +- 后续任务:无 +- 详细决策:`decision/14-conversation-rendering-hierarchy.md` + +## 目标 + +优化 Assistant Turn 的实时回答、Thinking、Tool Call 和 Subagent 展示层级,让用户优先看到当前答案,同时保留完整执行过程和现有流式性能设计。 + +## 固定方案 + +- 保留现有 OMP Runtime、RPC、Electron IPC 和 `OmpEventReducer` 主链路,不新增第二套事件协议或状态机。 +- 保留 `@assistant-ui/react` 和 `@assistant-ui/react-markdown`,不在本任务迁移到 Streamdown 或重写 Markdown Renderer。 +- Active Turn 继续直接渲染,不把每次 token 更新重新转换并 reconcile 全部历史消息。 +- `final` 仍只由现有成功结束规则确定;运行中的普通文本只增加展示层 `answer candidate` 语义,不提前修改数据层为 `final`。 +- 模型输出格式不作为本任务修改对象;先修 Renderer 的语义层级和 Markdown 排版。 +- UI 保持紧凑、白底、少边框;只有 Interaction、错误等需要用户注意的内容使用明显容器。 + +## 明确不做 + +- 不修改 OMP 的模型 Prompt 来强制制造标题或重点。 +- 不改变 `message_start/update/end`、`tool_execution_*` 和 `agent_end` 的归并语义。 +- 不把 Thinking、Tool Call 或 Subagent 拆成独立聊天消息。 +- 不为普通 Tool Call 增加多层详情卡片。 +- 不在性能测试证明必要前引入新的消息虚拟化或 Markdown AST 缓存。 + +## 任务清单 + +### 实时回答 + +- [x] 在 Active Assistant Turn 中派生展示层 `answer candidate`,不写入 Reducer 持久状态。 +- [x] 在整个 Active Assistant Turn 中,将末尾连续的非空普通文本 item 作为 `answer candidate`;没有 Tool Call 的纯问答场景同样适用。 +- [x] `answer candidate` 使用与最终回答接近的主文本样式,不继续使用低对比度 `.process-narrative` 样式。 +- [x] `answer candidate` 按原 item 分别使用与最终回答相同的 Markdown Renderer,显示在 Process 下方,不自动收起正在运行的 Process。 +- [x] `answer candidate` 忽略 Turn 尾部空 Text,使用 `smooth={false}` 和 `defer`,不增加二次平滑打字动画。 +- [x] 纯文本回答在运行中和完成后都不显示空 Process Summary;`redactedThinking` 完全隐藏。 +- [x] 如果后续出现新的 Tool Call,之前的 `answer candidate` 自动降级回过程文本并恢复原始顺序。 +- [x] Thinking 永远保持过程语义,不进入 `answer candidate`。 +- [x] `agent_end` 后继续使用现有 `classifyFinalAnswer` 作为最终回答唯一真值,不建立第二套 final 判断。 +- [x] 最终回答与实时候选回答切换时不重复显示同一段文本。 + +### 最终回答 Markdown + +- [x] 保留现有 assistant-ui Markdown 渲染链路,补齐标题、段落、列表、粗体、引用、链接、inline code 和 code block 的视觉层级。 +- [x] 引入并使用 `@tailwindcss/typography` 的 `prose` 体系,只作用于候选回答和最终回答;按 Desktop UI 缩小标题、段距和列表间距。 +- [x] 确保 `h1~h6`、`strong`、`blockquote`、inline code 不再被 Tailwind reset 后表现为接近普通正文的黑字。 +- [x] 保持 Assistant 回答无气泡、无头像、白底黑字,不把正文改成博客式大标题排版。 +- [x] 保留现有本地文件链接、外部链接和代码块交互能力。 +- [x] 引用使用左边线且不斜体;inline code 使用浅灰圆角背景并移除默认反引号装饰;代码块不自动换行,过宽时横向滚动。 + +### Tool Call + +- [x] 继续复用 Reducer 已有的 `context`、`command`、`edit`、`subagent`、`external` 分类,不增加新的协议字段。 +- [x] Context Tool 不再聚合;`read`、`grep`、`glob`、`find`、`ls`、`web_search` 和 `fetch` 在 Process 展开后按原始顺序逐条紧凑显示。 +- [x] Command Tool 使用紧凑命令语义,优先展示命令首行和运行状态。 +- [x] Edit Tool 使用文件修改语义,优先展示目标文件或路径和最终状态。 +- [x] External Tool 保留通用 Tool Row,未知工具不猜测业务含义。 +- [x] Tool 行使用图标、动作词、主要参数和状态建立差异,避免所有调用都表现为相同的“工具名 + 灰字”。 +- [x] Tool 行复用 `lucide-react`,采用“左侧工具类型 SVG 图标 + 短文字 + 右侧状态 SVG 图标”的紧凑结构,不新增自绘图标。 +- [x] Tool 行按已确认的逐工具动作词和 Lucide 图标映射显示;状态按 pending、running、success、error、rejected、aborted 和 incomplete 分支原位更新,不显示 `partialResult`,正常状态不重复显示文字标签。 +- [x] 文件参数优先显示 Workspace 相对路径;Workspace 外路径缩短为末尾两级,完整原值保留在 `title` 和无障碍文本中。 +- [x] 普通 Tool Call 保持单行或紧凑多行;错误、拒绝、中止状态提高视觉权重。 +- [x] 普通 Tool 成功后不显示结果摘要;复制入口只在悬停或键盘聚焦时出现,错误 Tool 可以一直显示。 + +### Subagent + +- [x] 为 `category === 'subagent'` 增加独立展示组件或专用 Tool Row 变体,不再完全复用普通 Tool Row 外观。 +- [x] 继续复用现有 `task`、`subagent`、`delegate` 分类结果,不修改 Runtime。 +- [x] 展示 Subagent 的任务名称或主要目标、运行状态和结果摘要;字段不足时回退到原始工具名。 +- [x] Subagent 结果摘要只在 Process 展开后显示,最多一行且不提供 Subagent 自身展开入口;批量 `tasks[]` 按一个 Tool Call 显示任务数量和合并摘要。 +- [x] Subagent 结果摘要不解析 Markdown,提取第一段有效文字并清理常见 Markdown 标记,最多约 160 个字符。 +- [x] Subagent 运行中、完成、失败和中止状态可一眼区分。 +- [x] 不在第一版展开完整子 Agent 对话树;只展示当前主 Run 需要理解的摘要。 + +### Thinking、Interaction 与层级 + +- [x] Thinking 使用更小字号和低对比度文本,明确低于当前回答和重要状态。 +- [x] Thinking 不增加图标、标签或斜体,使用 12px 弱灰色普通字重;过程 Text 13px,Tool 行 12px,回答正文 14px。 +- [x] 普通过程说明使用紧凑、低权重 Markdown,保持原始事件顺序;Thinking 继续使用纯文本。 +- [x] 过程 Text 复用本地路径校验和 `Ctrl+点击` 打开能力;Thinking 不提供路径交互。 +- [x] Interaction 保持当前结构化控件,继续在原始事件位置显示。 +- [x] Interaction、Tool Error 和需要用户决策的状态允许使用明显卡片或边框,其余过程信息尽量无卡片化。 +- [x] Tool Error 保持在 Tool 行内,显示最多 3 行实际错误、完整内容 `title` 和复制完整结果入口,不重复显示“执行失败”,不增加独立大卡片。 +- [x] Process Summary 使用“状态图标 · N 次工具调用 · 时长”的紧凑结构;只有等待用户操作时保留状态文字。 +- [x] Process Summary 按运行、完成、失败、中止和等待使用已确认的 Lucide 状态图标;失败时边框仍保持浅灰。 +- [x] Process Summary 使用最大宽度 32rem 的浅色圆角条;展开内容只保留左侧浅灰竖线,不增加完整外框或背景。 +- [x] Process 使用外层对话统一滚动,不设置内部最大高度、内部滚动或“回到过程底部”按钮;用户离开底部时不被流式更新强制拉回。 +- [x] Process Summary 时长包含 Agent 处理和等待用户操作的总时间;纯文本回答没有过程内容时不显示摘要。 +- [x] Process Summary 按唯一 `toolCallId` 计数;时长只使用当前运行期准确的 `agent_start` 到 `agent_end`,历史缺少边界时省略,不做近似或额外持久化。 +- [x] 等待用户确认时,摘要只显示“等待确认 · N秒”;处理后恢复状态图标、Tool 数量和总时长。 +- [x] Tool Approval 使用“等待确认”,输入或选择类 Interaction 使用“等待操作”;没有截止时间时省略倒计时。 +- [x] `completed-incomplete` 在界面上按正常完成处理;缺少结束事件的 Tool 只使用灰色 `CircleEllipsis` 图标,诊断详情写日志。 +- [x] 并行 Tool 不做特殊分组或连线,按原始声明顺序逐条显示并独立更新状态。 +- [x] 图标只使用现有 `lucide-react`,不新增图片、自绘 SVG 或复制外部美术资源;减少动态效果时通过 CSS 停止 Spinner 动画。 + +### 测试与回归 + +- [x] 在 `tests/renderer/conversation-thread.test.tsx` 覆盖实时 `answer candidate` 展示。 +- [x] 测试新 Tool Call 到达后旧候选文本自动降级为过程文本。 +- [x] 测试 Thinking 不会进入 `answer candidate`。 +- [x] 测试成功结束后仍由现有最终分类得到唯一最终回答。 +- [x] 测试 Process 展开后 Context Tool 不聚合,并按原始顺序逐条显示。 +- [x] 测试 `task`、`subagent`、`delegate` 都进入 Subagent 专用展示路径。 +- [x] 测试 Command、Edit、External 和错误 Tool 的展示分支。 +- [x] 测试纯文本回答不显示 Process Summary、候选回答不显示复制按钮、总时长包含等待时间。 +- [x] 测试失败或中止时候选文本回到 Process,`completed-incomplete` 不显示诊断文案,正常 Tool 不显示结果摘要。 +- [x] 测试 Process 无内部滚动,用户离开对话底部后流式更新不强制滚动。 +- [x] 测试实时完成与历史恢复共用展示规则,历史缺少准确生命周期时不显示时长。 +- [x] 测试空 Text 不打断候选、Tool 按唯一 ID 计数、等待确认时摘要隐藏数量和总时长。 +- [x] 测试纯文本运行态和 `redactedThinking` 不产生摘要、等待文案按 Interaction 类型区分、减少动态效果时 Spinner 不旋转。 +- [x] 回归长 Session 流式性能,确认 Active Turn 更新不会触发完整 settled history 重渲染。 +- [x] 运行 `pnpm check` 并通过现有 Renderer、Reducer 和性能测试。 + +## 完成条件 + +- [x] 模型生成时,用户能明显区分“当前回答”“Thinking”“Tool Call”“Subagent”和“需要操作的 Interaction”。 +- [x] 最后一个 Tool Call 后的当前回答在流式阶段已经具有正文层级,不需要等 `agent_end` 才变得可读。 +- [x] 新 Tool Call 到达时,之前的候选回答可以无重复、无丢失地回到过程区域。 +- [x] Markdown 标题、粗体、列表、引用和代码具有稳定视觉层级,不再表现为一整块相近黑字。 +- [x] Read、Search、Command、Edit、Subagent 和 External Tool 在不增加复杂卡片的前提下可快速区分。 +- [x] Subagent 不再与普通 Tool Call 完全同形,但仍保持紧凑。 +- [x] OMP Runtime、IPC、Reducer 事件语义和最终回答分类规则保持不变。 +- [x] 长 Session 的流式性能不低于现有实现。 diff --git a/TODO/in-progress/14-conversation-rendering-hierarchy.md b/TODO/in-progress/14-conversation-rendering-hierarchy.md deleted file mode 100644 index 324502f..0000000 --- a/TODO/in-progress/14-conversation-rendering-hierarchy.md +++ /dev/null @@ -1,96 +0,0 @@ -# POST-MVP-04:对话渲染层级与实时回答 - -- 状态:未开始 -- 优先级:P0 -- 前置任务:MVP-04 -- 后续任务:无 - -## 目标 - -优化 Assistant Turn 的实时回答、Thinking、Tool Call 和 Subagent 展示层级,让用户优先看到当前答案,同时保留完整执行过程和现有流式性能设计。 - -## 固定方案 - -- 保留现有 OMP Runtime、RPC、Electron IPC 和 `OmpEventReducer` 主链路,不新增第二套事件协议或状态机。 -- 保留 `@assistant-ui/react` 和 `@assistant-ui/react-markdown`,不在本任务迁移到 Streamdown 或重写 Markdown Renderer。 -- Active Turn 继续直接渲染,不把每次 token 更新重新转换并 reconcile 全部历史消息。 -- `final` 仍只由现有成功结束规则确定;运行中的普通文本只增加展示层 `answer candidate` 语义,不提前修改数据层为 `final`。 -- 模型输出格式不作为本任务修改对象;先修 Renderer 的语义层级和 Markdown 排版。 -- UI 保持紧凑、白底、少边框;只有 Interaction、错误等需要用户注意的内容使用明显容器。 - -## 明确不做 - -- 不修改 OMP 的模型 Prompt 来强制制造标题或重点。 -- 不改变 `message_start/update/end`、`tool_execution_*` 和 `agent_end` 的归并语义。 -- 不把 Thinking、Tool Call 或 Subagent 拆成独立聊天消息。 -- 不为普通 Tool Call 增加多层详情卡片。 -- 不在性能测试证明必要前引入新的消息虚拟化或 Markdown AST 缓存。 - -## 任务清单 - -### 实时回答 - -- [ ] 在 Active Assistant Turn 中派生展示层 `answer candidate`,不写入 Reducer 持久状态。 -- [ ] 将当前 Assistant Message 中最后一个 Tool Call 之后的普通非 Thinking 文本作为 `answer candidate` 显示。 -- [ ] `answer candidate` 使用与最终回答接近的主文本样式,不继续使用低对比度 `.process-narrative` 样式。 -- [ ] 如果后续出现新的 Tool Call,之前的 `answer candidate` 自动降级回过程文本并恢复原始顺序。 -- [ ] Thinking 永远保持过程语义,不进入 `answer candidate`。 -- [ ] `agent_end` 后继续使用现有 `classifyFinalAnswer` 作为最终回答唯一真值,不建立第二套 final 判断。 -- [ ] 最终回答与实时候选回答切换时不重复显示同一段文本。 - -### 最终回答 Markdown - -- [ ] 保留现有 assistant-ui Markdown 渲染链路,补齐标题、段落、列表、粗体、引用、链接、inline code 和 code block 的视觉层级。 -- [ ] 优先评估并使用 `@tailwindcss/typography` 的 `prose` 体系,避免手写一整套 Markdown CSS;按 Desktop UI 缩小标题、段距和列表间距。 -- [ ] 确保 `h1~h6`、`strong`、`blockquote`、inline code 不再被 Tailwind reset 后表现为接近普通正文的黑字。 -- [ ] 保持 Assistant 回答无气泡、无头像、白底黑字,不把正文改成博客式大标题排版。 -- [ ] 保留现有本地文件链接、外部链接和代码块交互能力。 - -### Tool Call - -- [ ] 继续复用 Reducer 已有的 `context`、`command`、`edit`、`subagent`、`external` 分类,不增加新的协议字段。 -- [ ] Context Tool 继续聚合,优先显示“读取 N 个文件 · 搜索 N 次”等已有结构化摘要。 -- [ ] Command Tool 使用紧凑命令语义,优先展示命令首行和运行状态。 -- [ ] Edit Tool 使用文件修改语义,优先展示目标文件或路径和最终状态。 -- [ ] External Tool 保留通用 Tool Row,未知工具不猜测业务含义。 -- [ ] Tool 行使用图标、动作词、主要参数和状态建立差异,避免所有调用都表现为相同的“工具名 + 灰字”。 -- [ ] 普通 Tool Call 保持单行或紧凑多行;错误、拒绝、中止状态提高视觉权重。 - -### Subagent - -- [ ] 为 `category === 'subagent'` 增加独立展示组件或专用 Tool Row 变体,不再完全复用普通 Tool Row 外观。 -- [ ] 继续复用现有 `task`、`subagent`、`delegate` 分类结果,不修改 Runtime。 -- [ ] 展示 Subagent 的任务名称或主要目标、运行状态和结果摘要;字段不足时回退到原始工具名。 -- [ ] Subagent 运行中、完成、失败和中止状态可一眼区分。 -- [ ] 不在第一版展开完整子 Agent 对话树;只展示当前主 Run 需要理解的摘要。 - -### Thinking、Interaction 与层级 - -- [ ] Thinking 使用更小字号和低对比度文本,明确低于当前回答和重要状态。 -- [ ] 普通过程说明保持原始事件顺序,但视觉权重低于 `answer candidate`。 -- [ ] Interaction 保持当前结构化控件,继续在原始事件位置显示。 -- [ ] Interaction、Tool Error 和需要用户决策的状态允许使用明显卡片或边框,其余过程信息尽量无卡片化。 -- [ ] Run Summary、Context Group、Tool Row、Subagent 和当前回答之间保持稳定的垂直节奏,避免连续灰色文本堆叠。 - -### 测试与回归 - -- [ ] 在 `tests/renderer/conversation-thread.test.tsx` 覆盖实时 `answer candidate` 展示。 -- [ ] 测试新 Tool Call 到达后旧候选文本自动降级为过程文本。 -- [ ] 测试 Thinking 不会进入 `answer candidate`。 -- [ ] 测试成功结束后仍由现有最终分类得到唯一最终回答。 -- [ ] 测试 Context 聚合行为保持不变。 -- [ ] 测试 `task`、`subagent`、`delegate` 都进入 Subagent 专用展示路径。 -- [ ] 测试 Command、Edit、External 和错误 Tool 的展示分支。 -- [ ] 回归长 Session 流式性能,确认 Active Turn 更新不会触发完整 settled history 重渲染。 -- [ ] 运行 `pnpm check` 并通过现有 Renderer、Reducer 和性能测试。 - -## 完成条件 - -- [ ] 模型生成时,用户能明显区分“当前回答”“Thinking”“Tool Call”“Subagent”和“需要操作的 Interaction”。 -- [ ] 最后一个 Tool Call 后的当前回答在流式阶段已经具有正文层级,不需要等 `agent_end` 才变得可读。 -- [ ] 新 Tool Call 到达时,之前的候选回答可以无重复、无丢失地回到过程区域。 -- [ ] Markdown 标题、粗体、列表、引用和代码具有稳定视觉层级,不再表现为一整块相近黑字。 -- [ ] Context、Command、Edit、Subagent 和 External Tool 在不增加复杂卡片的前提下可快速区分。 -- [ ] Subagent 不再与普通 Tool Call 完全同形,但仍保持紧凑。 -- [ ] OMP Runtime、IPC、Reducer 事件语义和最终回答分类规则保持不变。 -- [ ] 长 Session 的流式性能不低于现有实现。 diff --git a/decision/14-conversation-rendering-hierarchy.md b/decision/14-conversation-rendering-hierarchy.md new file mode 100644 index 0000000..01ade16 --- /dev/null +++ b/decision/14-conversation-rendering-hierarchy.md @@ -0,0 +1,81 @@ +# 决策记录 14:对话渲染层级与实时回答 + +- 对应任务:`TODO/done/14-conversation-rendering-hierarchy.md` +- 状态:已实现 +- 首次确认日期:2026-08-12 + +## 第一批确认决策 + +1. `answer candidate` 在整个 Active Assistant Turn 内派生,不局限于当前 Assistant Message。查找和降级都以 Turn 中的原始 item 顺序为准。 +2. Active Turn 尚未出现 Tool Call 时,Turn 末尾符合条件的非 Thinking 普通文本直接作为 `answer candidate`,纯问答场景不等待 `agent_end` 才显示正文层级。 +3. `answer candidate` 独立显示在 Process Summary 和展开的 Process Contents 下方,保持“过程在前、当前回答在后”的界面顺序。 +4. 流式阶段的 `answer candidate` 直接使用与最终回答相同的 Markdown Renderer、组件映射和安全限制;保留 `skipHtml`、本地路径和外部链接处理,不增加纯文本临时渲染链路。 +5. 候选范围包含多个普通文本 item 时,按原 item 分别交给 Markdown Renderer,并使用各自的稳定 ID,不先拼接字符串或主动插入换行。复制时仍可沿用现有原始文本拼接规则。 +6. `answer candidate` 只取 Active Turn 末尾连续的非空普通文本 item。最后一个 Tool Call 后如果又出现 Thinking、Interaction 或其他过程 item,该过程 item 之前的普通文本仍留在过程区域,只有末尾连续文本进入候选区域。 +7. `answer candidate` 出现时不自动收起正在运行的 Process。保留现有展开、用户手动收起、Interaction 到达时展开和 Turn 完成后自动收起规则。 +8. 引入 `@tailwindcss/typography`。`prose` 只用于 `answer candidate` 和 `classifyFinalAnswer` 确定的最终回答,不影响 Thinking、过程说明、Tool Call、Subagent、Interaction 和用户消息。 +9. Assistant Markdown 使用紧凑标题层级:正文 14px;h1 20px/650,h2 18px/650,h3 16px/600,h4 14px/600,h5 14px/600 且颜色稍弱,h6 12px/600 且颜色稍弱。标题间距按 Desktop 对话界面缩小,不使用博客式大标题。 +10. Tool 行采用“SVG 工具类型图标 + 短文字 + SVG 状态图标”的结构。图标复用现有 `lucide-react`,不新画图标或复制外部 SVG;工具类型图标位于左侧,状态图标位于右侧,整体使用小尺寸线性图标、中性颜色和紧凑间距。 + +## 第二批确认决策 + +11. 已知工具使用逐工具动作词:`read` 为“读取”,`grep` 为“搜索”,`glob` 为“匹配文件”,`find` 为“查找”,`ls` 为“浏览目录”,`web_search` 为“搜索网页”,`fetch` 为“获取网页”,`bash/shell/exec/command` 为“运行”,`edit` 为“修改”,`write` 为“写入”,`apply_patch` 为“应用修改”,`create_file` 为“创建”,`delete_file` 为“删除”,`task/subagent/delegate` 为“子任务”。External Tool 保留原始工具名。 +12. 工具类型图标按具体动作映射:`read` 使用 `FileText`,`grep/find` 使用 `Search`,`glob` 使用 `FileSearch`,`ls` 使用 `Folder`,`web_search/fetch` 使用 `Globe`,Command 使用 `SquareTerminal`,`edit/write` 使用 `FilePenLine`,`apply_patch` 使用 `FileDiff`,`create_file` 使用 `FilePlus2`,`delete_file` 使用 `Trash2`,Subagent 使用 `Bot`,External 使用 `Wrench`。 +13. Tool 状态显示规则固定为:pending 显示时钟图标和“等待执行”;running 显示 Spinner 和“运行中”;success 只显示绿色勾;error 显示红色警告图标和错误摘要;rejected 显示停止图标和“已拒绝”;aborted 显示停止图标和“已中止”;incomplete 显示灰色警告图标和“未完整结束”。状态图标提供中文无障碍说明。 +14. Tool 状态由现有 OMP 事件驱动,并按 `toolCallId` 原位更新同一个 ActionItem;不增加轮询、定时调度、debounce 或节流。`tool_execution_update.partialResult` 第一版不显示,避免把不稳定输出误作结构化进度。 +15. Tool 行优先显示 Workspace 相对路径。Workspace 外部路径缩短为末尾两级并加 `…/`;单行空间不足时省略;`title` 和无障碍文本保留完整原始路径;不能只显示文件名。 +16. 一个 Assistant Turn 在界面上保持一个整体,只包含一个可折叠 Process 和一个候选或最终回答。Process 展开后显示多个原始 item,但不把每个 Text 或 Tool 拆成顶层聊天消息。 +17. 普通过程 Text 使用低权重、紧凑的 Markdown 渲染,避免候选回答降级后暴露 `##`、`-` 等原始标记;不使用回答正文的 `prose` 标题层级。Thinking 继续按纯文本显示。 +18. 候选回答回退只在 Renderer 派生 item ID:Process 跳过当前候选 ID,候选区域渲染这些 ID。新 Thinking、Tool、Interaction 或 Artifact 到达后重新派生,旧候选按原索引回到 Process。不得移动、复制或修改 Reducer item;降级后关闭平滑打字动画,避免整段重新播放。 +19. 完全移除 Context Group。一个 Turn 只保留 Process 一级展开;Process 展开后,所有 Context Tool 与其他 Tool 一样逐条紧凑渲染,并保持原始顺序,不增加二级展开。 +20. Process Summary 不显示“Process 摘要”字样,使用动态文案:“正在处理 / 已完成 / 执行失败 / 已中止 · N 次工具调用 · 时长”;没有 Tool 时省略调用次数;等待状态继续显示剩余处理时间。摘要文字 12px、字重 500、行高 18px,状态使用次要文字色,次数和时间使用弱文字色,失败使用低饱和红色,箭头 14px,整行约 36px。 + +## 第三批确认决策 + +21. Subagent 结果摘要只在 Turn 的 Process 展开时显示;Process 收起时不单独暴露 Subagent。Subagent 行显示任务名、状态和最多一行结果摘要,过长时省略并在 `title` 中保留完整内容;Subagent 自身不提供展开入口。 +22. 一次 `task` Tool Call 包含批量 `tasks[]` 时,仍按一个 `toolCallId` 显示一条 Subagent 行,主信息显示任务数量,结束后显示一条合并结果摘要;不把批量任务拆成多行或子树。 +23. Thinking 不增加图标或“思考”标签,使用 12px 弱灰色普通字重;普通过程 Text 使用 13px 次要文字色;Tool 行使用 12px;候选和最终回答使用 14px 主文字色。中文 Thinking 不使用斜体。 +24. Tool Error 不使用独立大卡片,继续在 Tool 行内显示红色警告图标、“执行失败”和最多 3 行错误摘要;超出后省略,完整错误保留在 `title`,并保留复制完整结果入口。 +25. 对话区只在用户位于底部时自动跟随流式更新;用户向上滚动后保持当前位置并显示“回到底部”按钮,点击后恢复自动跟随。 +26. Process 展开后不设置内部最大高度或内部滚动,不提供“回到过程底部”按钮;完整内容撑高对话,统一使用外层对话滚动。历史 Process 默认收起,Active Turn 由外层对话跟随底部。 +27. 流式 `answer candidate` 不显示复制按钮;只有 `agent_end` 后确定为最终回答,才显示现有复制入口。 +28. 完成的 Turn 只有最终普通文本、没有 Thinking、过程 Text、Tool、Subagent、Interaction 或错误时,不显示 Process Summary,直接显示最终回答。 +29. Process Summary 只显示一个总时长,包含 Agent 处理时间和等待用户操作的时间;不扣除或单列等待时长。 +30. 并行 Tool 不做特殊分组。Renderer 不推断 OMP 未提供的并行关系;多个 Tool 按原始声明顺序逐条显示,各自独立显示当前状态,不增加连线、并行组或串行组。 + +## 第四批确认决策 + +31. Turn 失败或中止时,当前 `answer candidate` 降回 Process,不作为最终回答留在 Process 外;Process 保持展开,未完成文本和错误继续按原始位置显示。 +32. `completed-incomplete` 在用户界面按正常完成处理:Process Summary 显示完成图标并自动收起,不显示“记录不完整”。用户手动展开后,未收到结束事件的 Tool 只显示灰色 `CircleEllipsis` 图标,不显示“状态未知”文字;诊断详情只写日志。 +33. 整个流式输出统一采用“能用 UI 表达就不重复写状态文字”的原则。正常状态优先使用图标、动画、颜色、位置和层级;不显示“运行中”“成功”“状态未知”“执行失败”等可由 UI 表达的标签。文字只保留动作、目标、实际错误、结果摘要和需要用户操作的提示。纯图形状态必须保留 `aria-label`。本条覆盖第 13、20、24 条中的重复状态文字规则。 +34. Process Summary 中的计数文案保留精确表述“N 次工具调用”,不简化为“N 个操作”。 +35. Process Summary 使用可点击的浅色圆角条:1px 浅边框、白色或极浅灰背景、8px 圆角、无阴影、高度约 36px。 +36. Process Summary 不占满 Assistant 消息宽度,使用 `width: min(100%, 32rem)`,最大约 512px。 +37. Process 展开内容保留 1px 浅灰色左侧竖线,用于表示内容属于当前 Process;不增加完整外框或背景。 +38. Process 与候选回答之间不显示“回答”标签或分割线,只保留约 12px 垂直间距,由字号和文字颜色区分层级。 +39. 已结束 Tool 的复制图标默认隐藏,只在 Tool 行悬停或键盘聚焦时显示;错误 Tool 的复制入口可以一直显示。 +40. 普通 Tool 成功后不显示结果摘要,只显示工具图标、动作、主要参数和成功图标。Subagent 可以显示结果摘要;错误 Tool 显示实际错误内容。 + +## 第五批确认决策 + +41. 流式 `answer candidate` 不增加 assistant-ui 的平滑打字动画,使用 `smooth={false}` 直接显示 OMP 实际到达的文本;保留 `defer`,降低 Markdown 解析对紧急更新的影响。 +42. 候选和最终回答的 `blockquote` 使用 2px 左边线、次要文字色且不使用斜体;inline code 使用浅灰背景、4px 圆角、12px 等宽字体且无边框,并移除 `prose` 默认添加的反引号装饰。本条不作用于 Thinking。 +43. 候选和最终回答的代码块不自动换行,保留代码格式;内容过宽时由代码块内部横向滚动。 +44. Active Turn 尾部的空字符串或纯空白 Text item 不打断候选范围;派生候选 ID 时忽略空 Text 并继续向前查找末尾普通文本。 +45. 实时 Turn 完成后的展示与重新加载 Session 历史后的展示必须同形:使用相同的 item 顺序、图标、文案、Markdown、折叠和 Tool 状态规则,并共用同一个展示派生函数。 +46. Process Summary 时长只使用准确的 Turn 生命周期边界,即当前运行期收到 `agent_start` 到 `agent_end` 的总时间。重新加载历史后,`get_messages` 没有保存准确生命周期边界时省略时长;不使用消息时间近似,也不新增持久化时间记录。 +47. Process Summary 的 Tool 数量按唯一 `toolCallId` 计数,成功、失败、拒绝和中止都计入;一次批量 Subagent 调用只有一个 `toolCallId`,因此计为一次。 +48. 总时长不显示小数:小于 1 秒显示“少于 1 秒”,小于 1 分钟显示“N秒”,小于 1 小时显示“N分N秒”,达到 1 小时后显示“N小时N分”并省略秒。 +49. 普通过程 Text 的 Markdown 文件链接和行内有效路径继续支持 `Ctrl+点击`,复用最终回答现有的本地路径校验和打开逻辑;Thinking 不提供该交互。 +50. 等待用户确认期间,Process Summary 只显示必要的“等待确认 · N秒”倒计时,暂时省略 Tool 数量和总时长;用户处理后恢复图形状态、“N 次工具调用”和总时长。 + +## 计划结束时确认的剩余决策 + +51. 纯文本回答在流式生成期间如果没有 Thinking、过程 Text、Tool、Subagent、Interaction 或错误,也不显示 Process Summary,只显示 `answer candidate` 和输入区现有 Stop 控件。 +52. OMP 返回 `redactedThinking` 时完全隐藏该 item,不显示“思考内容不可用”,也不因此创建 Process Summary。 +53. 失败的 Process Summary 继续使用普通浅灰边框,不把整条边框改成红色;只有状态警告图标和实际错误文字使用低饱和红色。 +54. Process Summary 左侧状态图标固定为:运行使用 `LoaderCircle`,完成使用 `Check`,失败使用 `CircleAlert`,中止使用 `CircleStop`,等待使用 `CircleHelp`。实际界面只显示 SVG,不显示对应状态文字;所有图标保留 `aria-label`。 +55. 等待状态文案按交互类型区分:Tool Approval 显示“等待确认 · N秒”,输入或选择类 Interaction 显示“等待操作 · N秒”;没有截止时间时只显示“等待操作”。 +56. 本任务不新增图片或自绘 SVG。图标全部来自仓库已有的 `lucide-react 1.25.0`;Markdown 继续使用 `@assistant-ui/react-markdown 0.14.6`;圆角、边框、颜色、间距和 Spinner 使用项目 CSS;字体使用系统字体栈;`@tailwindcss/typography` 只提供排版 CSS。不得从 ChatGPT 或外部参考项目复制美术资源。 +57. Subagent 结果摘要不解析 Markdown。提取第一段有效文字,压成单行,最多约 160 个字符,并去掉标题、列表等常见 Markdown 标记;完整原始结果仍通过复制入口取得。 +58. 系统 `prefers-reduced-motion: reduce` 生效时,通过 CSS 停止 Tool 和 Process Spinner 动画,但保留图标及 `aria-label`;不增加应用内设置、React 状态或 IPC。 diff --git a/docs/desktop-architecture.md b/docs/desktop-architecture.md index bb03cd3..cde9bda 100644 --- a/docs/desktop-architecture.md +++ b/docs/desktop-architecture.md @@ -245,7 +245,7 @@ Renderer 将 OMP 实时事件和 Session 历史转换为同一种有序展示投 - `Artifact`:高价值工具结果的引用或摘要。 - `Lifecycle`:运行状态和控制信号,不属于聊天内容。 -该投影必须保持薄层。它不持久化第二份 Session 历史,不调度工具,也不推断 OMP 未提供的 Agent 状态。Context Action 聚合只影响展示,展开时仍恢复原始操作顺序。 +该投影必须保持薄层。它不持久化第二份 Session 历史,不调度工具,也不推断 OMP 未提供的 Agent 状态。Process 只提供 Turn 级一级展开;展开后,各类 Action 按原始顺序逐条显示。 ### Renderer 持有 diff --git a/docs/desktop-ui-implementation-and-reference-workflow.md b/docs/desktop-ui-implementation-and-reference-workflow.md index ec5b04e..a8208a7 100644 --- a/docs/desktop-ui-implementation-and-reference-workflow.md +++ b/docs/desktop-ui-implementation-and-reference-workflow.md @@ -88,7 +88,7 @@ agent_start / agent_end Renderer 只做事件归并和展示,不重建 Agent 状态机。 -Tool Call、Progress 和 Result 使用 `toolCallId` 更新同一个 Action。连续的 Read、Grep、Glob、List 和 Web Search 等上下文操作可以聚合显示;聚合只影响展示,展开后必须恢复原始工具顺序。 +Tool Call、Progress 和 Result 使用 `toolCallId` 更新同一个 Action。Read、Grep、Glob、List 和 Web Search 等上下文操作不再建立二级聚合;Process 展开后按原始顺序逐条紧凑显示。 ## 4. Thinking 和工具调用的交互 diff --git a/docs/product-spec.md b/docs/product-spec.md index de281f7..2a80f2b 100644 --- a/docs/product-spec.md +++ b/docs/product-spec.md @@ -112,10 +112,11 @@ MVP 的一个活动 Workspace 只有一个长期运行的 OMP Runtime。同一 - 生成过程中展开一个连续的 Process,普通文字、Thinking 和工具操作保持原始顺序。 - 同一次工具调用的开始、进度、结果和错误显示为一个操作,不拆成多张卡片。 -- 连续的读取、搜索、遍历等低价值上下文操作聚合显示,用户展开后仍可查看原始顺序。 +- 回复结束后,完整过程统一收起为一条摘要;用户展开后,读取、搜索、遍历等上下文操作与其他工具调用一样按原始顺序逐条紧凑显示,不增加二级分组。 - 回复结束后自动收起过程信息。 - 最终默认只突出 Assistant 的最终回答。 - 用户可以手动展开历史过程。 +- 展开的过程不建立内部滚动区域,统一随对话主区滚动;用户离开底部后,流式更新不能强制拉回。 - Permission 等待时在对应工具操作的位置展开;处理后收起交互控件,但保留工具最终状态。 - 运行状态只控制状态提示、Spinner、Stop 和错误展示,不作为普通聊天消息。 - Agent 运行中再次发送的普通消息进入 Follow-up 队列,并按发送顺序逐条执行。 diff --git "a/docs/\346\265\201\345\274\217\350\276\223\345\207\272\345\206\263\347\255\226.md" "b/docs/\346\265\201\345\274\217\350\276\223\345\207\272\345\206\263\347\255\226.md" index 8f3b05e..f071ba3 100644 --- "a/docs/\346\265\201\345\274\217\350\276\223\345\207\272\345\206\263\347\255\226.md" +++ "b/docs/\346\265\201\345\274\217\350\276\223\345\207\272\345\206\263\347\255\226.md" @@ -12,7 +12,7 @@ | 项目 | 核心做法 | 我们借鉴什么 | | -------- | -------------------------------------------------------------------------------------------------------- | --------------------------------- | | Goose | Thinking、普通文本、工具卡片。工具调用和结果在同一卡片中,审批也放在卡片内。 | 工具操作统一成一个 Action | -| OpenCode | 基础 Part 是 Text、Reasoning、Tool。连续的 Read、Glob、Grep、List 会聚合成一个 Context Group。 | 低价值工具聚合,不逐条占空间 | +| OpenCode | 基础 Part 是 Text、Reasoning、Tool。连续的 Read、Glob、Grep、List 会聚合成一个 Context Group。 | 参考其 Tool 语义,不采用二级聚合 | | Zed | 审批显示在对应工具卡片中。文件变化单独进入 Review Changes,可以按 Hunk 接受或拒绝。([Zed][1]) ([Zed][2]) | Approval 和 Diff 都不能当普通日志 | --- @@ -69,7 +69,7 @@ OMP 已经提供: ### Context Action -以下工具连续出现时自动聚合: +以下工具继续归类为 Context Action: ```text read @@ -79,13 +79,15 @@ list web search ``` -显示为: +Process 展开后逐条紧凑显示,例如: ```text -Gathered context · 8 files · 3 searches ▸ +读取 src/app.ts +搜索 classifyFinalAnswer +浏览 src/renderer ``` -这直接采用 OpenCode 的做法。 +不再建立 Context Group 或二级展开。完整 Process 由 Turn 级摘要统一收起。 --- diff --git a/package.json b/package.json index 6027161..c32a842 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@eslint/js": "^9.39.1", "@radix-ui/react-dialog": "^1.1.20", "@radix-ui/react-popover": "^1.1.20", + "@tailwindcss/typography": "^0.5.20", "@tailwindcss/vite": "^4.3.3", "@tanstack/react-virtual": "^3.14.8", "@testing-library/jest-dom": "^7.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8a3b9c..92002b7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,10 +20,10 @@ importers: devDependencies: '@assistant-ui/react': specifier: 0.14.27 - version: 0.14.27(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 0.14.27(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@assistant-ui/react-markdown': specifier: 0.14.6 - version: 0.14.6(@assistant-ui/react@0.14.27(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(supports-color@7.2.0) + version: 0.14.6(@assistant-ui/react@0.14.27(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(supports-color@7.2.0) '@electron-toolkit/tsconfig': specifier: ^2.0.0 version: 2.0.0(@types/node@24.13.3) @@ -32,10 +32,13 @@ importers: version: 9.39.5 '@radix-ui/react-dialog': specifier: ^1.1.20 - version: 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-popover': specifier: ^1.1.20 - version: 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@tailwindcss/typography': + specifier: ^0.5.20 + version: 0.5.20(tailwindcss@4.3.3) '@tailwindcss/vite': specifier: ^4.3.3 version: 4.3.3(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)) @@ -47,7 +50,7 @@ importers: version: 7.0.0(@testing-library/dom@10.4.1) '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/node': specifier: ^24.0.0 version: 24.13.3 @@ -56,13 +59,13 @@ importers: version: 19.2.17 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.17) + version: 19.2.4(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^5.1.1 version: 5.2.0(supports-color@7.2.0)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)) cmdk: specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) electron: specifier: ^39.2.6 version: 39.8.10(supports-color@7.2.0) @@ -1763,6 +1766,11 @@ packages: resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} engines: {node: '>= 20'} + '@tailwindcss/typography@0.5.20': + resolution: {integrity: sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==} + peerDependencies: + tailwindcss: '>=3.0.0 || >=4.0.0 || insiders' + '@tailwindcss/vite@4.3.3': resolution: {integrity: sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==} peerDependencies: @@ -1869,8 +1877,8 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + '@types/react-dom@19.2.4': + resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} peerDependencies: '@types/react': ^19.2.0 @@ -2328,6 +2336,11 @@ packages: css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -3532,6 +3545,10 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + postcss@8.5.20: resolution: {integrity: sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==} engines: {node: ^10 || ^12 || >=14} @@ -4474,10 +4491,10 @@ snapshots: - ioredis - redis - '@assistant-ui/react-markdown@0.14.6(@assistant-ui/react@0.14.27(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(supports-color@7.2.0)': + '@assistant-ui/react-markdown@0.14.6(@assistant-ui/react@0.14.27(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(supports-color@7.2.0)': dependencies: - '@assistant-ui/react': 0.14.27(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@assistant-ui/react': 0.14.27(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) classnames: 2.5.1 react: 19.2.7 @@ -4489,23 +4506,23 @@ snapshots: - react-dom - supports-color - '@assistant-ui/react@0.14.27(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@assistant-ui/react@0.14.27(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@assistant-ui/core': 0.2.21(@assistant-ui/store@0.2.20(@assistant-ui/tap@0.9.4(@types/react@19.2.17)(react@19.2.7))(@types/react@19.2.17)(react@19.2.7))(@assistant-ui/tap@0.9.4(@types/react@19.2.17)(react@19.2.7))(@types/react@19.2.17)(assistant-cloud@0.1.35)(react@19.2.7)(zustand@5.0.14(@types/react@19.2.17)(react@19.2.7)) '@assistant-ui/store': 0.2.20(@assistant-ui/tap@0.9.4(@types/react@19.2.17)(react@19.2.7))(@types/react@19.2.17)(react@19.2.7) '@assistant-ui/tap': 0.9.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-escape-keydown': 1.1.3(@types/react@19.2.17)(react@19.2.7) assistant-cloud: 0.1.35 assistant-stream: 0.3.26 nanoid: 6.0.0 - radix-ui: 1.6.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + radix-ui: 1.6.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) react-textarea-autosize: 8.5.9(@types/react@19.2.17)(react@19.2.7) @@ -4514,7 +4531,7 @@ snapshots: zustand: 5.0.14(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) transitivePeerDependencies: - immer - ioredis @@ -5093,68 +5110,68 @@ snapshots: '@radix-ui/primitive@1.1.6': {} - '@radix-ui/react-accessible-icon@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-accessible-icon@1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-accordion@1.2.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-accordion@1.2.17(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collapsible': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collapsible': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-alert-dialog@1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-alert-dialog@1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dialog': 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-arrow@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-arrow@1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-aspect-ratio@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-aspect-ratio@1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-avatar@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-avatar@1.2.3(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -5162,50 +5179,50 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-checkbox@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-checkbox@1.3.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-collapsible@1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-collapsible@1.1.17(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-collection@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-collection@1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -5213,18 +5230,18 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-context-menu@2.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-context-menu@2.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-context@1.2.0(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -5232,18 +5249,18 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-dialog@1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dialog@1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -5253,7 +5270,7 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-direction@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -5261,33 +5278,33 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-dismissable-layer@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dismissable-layer@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-dropdown-menu@2.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dropdown-menu@2.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -5295,47 +5312,47 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-focus-scope@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-focus-scope@1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-form@0.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-form@0.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-label': 2.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-label': 2.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-hover-card@1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-hover-card@1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -5344,31 +5361,31 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-label@2.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-label@2.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-menu@2.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-menu@2.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) aria-hidden: 1.2.6 @@ -5377,58 +5394,58 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-menubar@1.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-menubar@1.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-navigation-menu@1.2.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-navigation-menu@1.2.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-one-time-password-field@0.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-one-time-password-field@0.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) @@ -5437,15 +5454,15 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-password-toggle-field@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-password-toggle-field@0.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) @@ -5453,21 +5470,21 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-popover@1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-popover@1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) aria-hidden: 1.2.6 @@ -5476,15 +5493,15 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-popper@1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-popper@1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@floating-ui/react-dom': 2.1.9(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-arrow': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-arrow': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-rect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -5494,72 +5511,72 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-portal@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-portal@1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-presence@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-presence@1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-primitive@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-primitive@2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-progress@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-progress@1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-radio-group@1.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-radio-group@1.4.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-roving-focus@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-roving-focus@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) @@ -5568,73 +5585,73 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-scroll-area@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-scroll-area@1.2.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-select@2.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-select@2.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) aria-hidden: 1.2.6 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-separator@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-separator@1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-slider@1.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-slider@1.4.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -5643,7 +5660,7 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-slot@1.3.0(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -5652,117 +5669,117 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-switch@1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-switch@1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-tabs@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-tabs@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-toast@1.2.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-toast@1.2.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-toggle-group@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-toggle-group@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-toggle': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-toggle@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-toggle@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-toolbar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-toolbar@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-separator': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-toggle-group': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-separator': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle-group': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-tooltip@1.2.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-tooltip@1.2.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.6 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -5825,14 +5842,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-visually-hidden@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-visually-hidden@1.2.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/rect@1.1.2': {} @@ -5982,6 +5999,11 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + '@tailwindcss/typography@0.5.20(tailwindcss@4.3.3)': + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 4.3.3 + '@tailwindcss/vite@4.3.3(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0))': dependencies: '@tailwindcss/node': 4.3.3 @@ -6018,7 +6040,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@babel/runtime': 7.29.7 '@testing-library/dom': 10.4.1 @@ -6026,7 +6048,7 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@types/aria-query@5.0.4': {} @@ -6116,7 +6138,7 @@ snapshots: dependencies: undici-types: 7.18.2 - '@types/react-dom@19.2.3(@types/react@19.2.17)': + '@types/react-dom@19.2.4(@types/react@19.2.17)': dependencies: '@types/react': 19.2.17 @@ -6616,12 +6638,12 @@ snapshots: dependencies: mimic-response: 1.0.1 - cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + cmdk@1.1.1(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dialog': 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) transitivePeerDependencies: @@ -6669,6 +6691,8 @@ snapshots: css.escape@1.5.1: {} + cssesc@3.0.0: {} + csstype@3.2.3: {} damerau-levenshtein@1.0.8: {} @@ -8207,6 +8231,11 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss@8.5.20: dependencies: nanoid: 3.3.16 @@ -8266,55 +8295,55 @@ snapshots: quick-lru@5.1.1: {} - radix-ui@1.6.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + radix-ui@1.6.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@radix-ui/primitive': 1.1.6 - '@radix-ui/react-accessible-icon': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-accordion': 1.2.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-alert-dialog': 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-arrow': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-aspect-ratio': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-avatar': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-checkbox': 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-collapsible': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-accessible-icon': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-accordion': 1.2.17(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-alert-dialog': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-arrow': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-aspect-ratio': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-avatar': 1.2.3(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-checkbox': 1.3.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collapsible': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.2.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-context-menu': 2.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-dialog': 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-context-menu': 2.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-dropdown-menu': 2.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dropdown-menu': 2.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-form': 0.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-hover-card': 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-label': 2.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-menubar': 1.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-navigation-menu': 1.2.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-one-time-password-field': 0.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-password-toggle-field': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-popover': 1.1.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-progress': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-radio-group': 1.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-scroll-area': 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-select': 2.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-separator': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-slider': 1.4.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-form': 0.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-hover-card': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-label': 2.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menu': 2.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menubar': 1.1.21(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-navigation-menu': 1.2.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-one-time-password-field': 0.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-password-toggle-field': 0.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popover': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-progress': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-radio-group': 1.4.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-scroll-area': 1.2.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-select': 2.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-separator': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slider': 1.4.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-switch': 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-tabs': 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-toast': 1.2.20(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-toggle': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-toggle-group': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-toolbar': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-tooltip': 1.2.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-switch': 1.3.4(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-tabs': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toast': 1.2.20(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle-group': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toolbar': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-tooltip': 1.2.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) @@ -8322,12 +8351,12 @@ snapshots: '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.8(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) react-dom@19.2.7(react@19.2.7): dependencies: diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx index 640b7bc..b83fad0 100644 --- a/src/renderer/app.tsx +++ b/src/renderer/app.tsx @@ -850,6 +850,7 @@ function Conversation({ }} projection={projection} setProjection={setProjection} + workspacePath={runtime.workspacePath} > {conversation} diff --git a/src/renderer/conversation-thread.tsx b/src/renderer/conversation-thread.tsx index ff13b67..d67925b 100644 --- a/src/renderer/conversation-thread.tsx +++ b/src/renderer/conversation-thread.tsx @@ -2,25 +2,40 @@ import { AssistantRuntimeProvider, MessagePartPrimitive, MessagePrimitive, + TextMessagePartProvider, ThreadPrimitive, useAuiState, useExternalStoreRuntime, useThreadViewport, type AppendMessage, - type PartState, type ThreadMessageLike } from '@assistant-ui/react' import { MarkdownTextPrimitive } from '@assistant-ui/react-markdown' import { ArrowDown, + Bot, Check, ChevronDown, ChevronRight, CircleAlert, + CircleEllipsis, + CircleHelp, CircleStop, + Clock3, Copy, + FileDiff, + FilePenLine, + FilePlus2, + FileSearch, + FileText, + Folder, + Globe, LoaderCircle, - Wrench + Search, + SquareTerminal, + Trash2, + Wrench, + type LucideIcon } from 'lucide-react' import { createContext, @@ -43,17 +58,18 @@ import { setTurnCollapsed, shouldCollapseTurn, turnElapsedMs, - turnStatusText, type ActionItem, type AssistantTurn, type ArtifactItem, type ConversationProjection, - type InteractionItem + type InteractionItem, + type NarrativeItem } from './omp-event-reducer' type ConversationContextValue = { projection: ConversationProjection setProjection: React.Dispatch> + workspacePath?: string } const ConversationContext = createContext(null) @@ -215,11 +231,20 @@ function CopyActionButton({ } function statusIcon(action: ActionItem): ReactNode { - if (action.state === 'running' || action.state === 'pending') { + if (action.state === 'pending') { + return ( + + ) + } + if (action.state === 'running') { return ( ) @@ -231,17 +256,155 @@ function statusIcon(action: ActionItem): ReactNode { return } if (action.state === 'aborted' || action.state === 'rejected') { - return + return ( + + ) } return ( - ) } +function argumentText( + action: ActionItem, + keys: readonly string[] +): string | undefined { + for (const key of keys) { + const value = action.args?.[key] + if (typeof value === 'string' && value.trim()) return value.trim() + } + return undefined +} + +function shortenPath(value: string, workspacePath?: string): string { + const normalized = value.replaceAll('\\', '/').replace(/\/+$/u, '') + const workspace = workspacePath?.replaceAll('\\', '/').replace(/\/+$/u, '') + if (workspace && normalized.startsWith(`${workspace}/`)) { + return normalized.slice(workspace.length + 1) + } + if (!/^(?:[a-z]:\/|\/)/iu.test(normalized)) return normalized + const parts = normalized.split('/').filter(Boolean) + return parts.length > 2 ? `…/${parts.slice(-2).join('/')}` : normalized +} + +function cleanInlineSummary(value: string | undefined): string | undefined { + if (!value) return undefined + const paragraph = value + .split(/\n\s*\n/u) + .find((part) => part.trim().length > 0) + if (!paragraph) return undefined + const cleaned = paragraph + .replace(/^\s{0,3}#{1,6}\s+/gmu, '') + .replace(/^\s*(?:[-*+] |\d+[.)] )/gmu, '') + .replace(/!\[([^\]]*)\]\([^)]*\)/gu, '$1') + .replace(/\[([^\]]+)\]\([^)]*\)/gu, '$1') + .replace(/[*_~`>#]/gu, '') + .replace(/\s+/gu, ' ') + .trim() + if (!cleaned) return undefined + return cleaned.length > 160 ? `${cleaned.slice(0, 159)}…` : cleaned +} + +type ToolPresentation = { + Icon: LucideIcon + label: string + detail?: string + detailTitle?: string +} + +function actionPresentation( + action: ActionItem, + workspacePath?: string +): ToolPresentation { + const name = action.toolName.toLowerCase() + const path = argumentText(action, ['path', 'filePath', 'directory']) + const pathDetail = path ? shortenPath(path, workspacePath) : undefined + if (name === 'read') + return { + Icon: FileText, + label: '读取', + detail: pathDetail, + detailTitle: path + } + if (name === 'grep') + return { + Icon: Search, + label: '搜索', + detail: argumentText(action, ['pattern', 'query']) + } + if (name === 'glob') + return { + Icon: FileSearch, + label: '匹配文件', + detail: argumentText(action, ['pattern', 'query']) + } + if (name === 'find') + return { + Icon: Search, + label: '查找', + detail: argumentText(action, ['query', 'pattern']) ?? pathDetail, + detailTitle: path + } + if (name === 'ls') + return { + Icon: Folder, + label: '浏览目录', + detail: pathDetail, + detailTitle: path + } + if (name === 'web_search') + return { + Icon: Globe, + label: '搜索网页', + detail: argumentText(action, ['query']) + } + if (name === 'fetch') + return { + Icon: Globe, + label: '获取网页', + detail: argumentText(action, ['url', 'target']) ?? pathDetail, + detailTitle: path + } + if (['bash', 'shell', 'exec', 'command'].includes(name)) { + const command = argumentText(action, ['command', 'cmd']) + return { + Icon: SquareTerminal, + label: '运行', + detail: command?.split(/\r?\n/u)[0], + detailTitle: command + } + } + const editTools: Record = { + edit: { Icon: FilePenLine, label: '修改' }, + write: { Icon: FilePenLine, label: '写入' }, + apply_patch: { Icon: FileDiff, label: '应用修改' }, + create_file: { Icon: FilePlus2, label: '创建' }, + delete_file: { Icon: Trash2, label: '删除' } + } + const edit = editTools[name] + if (edit) return { ...edit, detail: pathDetail, detailTitle: path } + if (action.category === 'subagent') { + const tasks = action.args?.['tasks'] + const detail = Array.isArray(tasks) + ? `${tasks.length} 个任务` + : argumentText(action, ['name', 'task']) + return { Icon: Bot, label: '子任务', detail } + } + return { + Icon: Wrench, + label: action.toolName, + detail: actionSummary(action) + } +} + function findToolResult(messages: unknown, toolCallId: string): unknown { const list: unknown[] = Array.isArray(messages) ? messages @@ -259,15 +422,14 @@ function findToolResult(messages: unknown, toolCallId: string): unknown { return undefined } -function ToolRow({ - action, - compact = false -}: { - action: ActionItem - compact?: boolean -}): React.JSX.Element { +function ToolRow({ action }: { action: ActionItem }): React.JSX.Element { const [copied, setCopied] = useState(false) - const summary = actionSummary(action) + const { workspacePath } = useConversationContext() + const presentation = actionPresentation(action, workspacePath) + const resultSummary = + action.category === 'subagent' && action.state === 'success' + ? cleanInlineSummary(action.resultSummary) + : undefined const copyResult = async (): Promise => { const result = await window.desktop.getMessages() if (!result.ok) return @@ -281,15 +443,24 @@ function ToolRow({ } return (
- {statusIcon(action)} - {action.toolName} - {summary && {summary}} - - {action.error ?? (action.state === 'incomplete' ? '未完整结束' : '')} + + + {presentation.label} + + {presentation.detail} + + {statusIcon(action)} {action.ended && ( )} + {resultSummary && ( + + {resultSummary} + + )} + {action.error && ( + + {action.error} + + )}
) } @@ -358,117 +539,6 @@ function ActionWithInteraction({ ) } -function contextSummary( - turn: AssistantTurn, - indices: readonly number[] -): string { - const actions = indices.flatMap((index): ActionItem[] => { - const item = turn.items[index] - return item?.kind === 'action' ? [item] : [] - }) - const paths = new Set() - let searches = 0 - for (const action of actions) { - const path = - action.args?.['path'] ?? - action.args?.['filePath'] ?? - action.args?.['directory'] - if (typeof path === 'string' && path.trim()) { - paths.add(path.replaceAll('\\', '/').replace(/\/+$/u, '')) - } - if ( - ['grep', 'glob', 'find', 'web_search'].includes( - action.toolName.toLowerCase() - ) - ) { - searches += 1 - } - } - const parts = [ - paths.size ? `读取 ${paths.size} 个文件` : undefined, - searches ? `搜索 ${searches} 次` : undefined - ].filter(Boolean) - return parts.length > 0 - ? parts.join(' · ') - : `执行了 ${actions.length} 次上下文操作` -} - -function LiveProcessItems({ - turn -}: { - turn: AssistantTurn -}): React.JSX.Element { - const nodes: Array< - | { kind: 'context'; actions: ActionItem[] } - | { kind: 'item'; item: AssistantTurn['items'][number] } - > = [] - for (const item of turn.items) { - if (item.kind === 'narrative' && item.narrative === 'final') continue - const groupable = - item.kind === 'action' && - item.category === 'context' && - !['error', 'rejected', 'aborted'].includes(item.state) - const previous = nodes.at(-1) - if (groupable && previous?.kind === 'context') { - previous.actions.push(item) - } else if (groupable) { - nodes.push({ kind: 'context', actions: [item] }) - } else { - nodes.push({ kind: 'item', item }) - } - } - return ( - <> - {nodes.map((node) => { - if (node.kind === 'context') { - const indices = node.actions.map((action) => - turn.items.findIndex((item) => item.id === action.id) - ) - return ( -
-
- - {contextSummary(turn, indices)} -
- {node.actions.map((action) => ( - - ))} -
- ) - } - const item = node.item - if (item.kind === 'narrative') { - return ( -
- {item.text} -
- ) - } - if (item.kind === 'action') { - return ( - - ) - } - if (item.kind === 'interaction' && !item.actionId) { - return - } - return null - })} -
- - 正在处理 -
- - ) -} - function Interaction({ interaction }: { @@ -744,144 +814,120 @@ const markdownComponents = { ) } -function ProcessContents({ +function answerCandidateItems(turn: AssistantTurn): NarrativeItem[] { + const items: NarrativeItem[] = [] + for (let index = turn.items.length - 1; index >= 0; index -= 1) { + const item = turn.items[index] + if (!item) continue + if (item.kind === 'narrative' && item.redacted) continue + if ( + item.kind === 'narrative' && + item.narrative === 'intermediate' && + !item.text.trim() + ) { + continue + } + if (item.kind === 'narrative' && item.narrative === 'intermediate') { + items.unshift(item) + continue + } + break + } + return items +} + +function processItems( + turn: AssistantTurn, + candidateIds: ReadonlySet = new Set() +): AssistantTurn['items'] { + return turn.items.filter((item) => { + if (item.kind === 'artifact') return false + if (item.kind !== 'narrative') return true + return ( + item.narrative !== 'final' && + !item.redacted && + (item.narrative === 'reasoning' || item.text.trim().length > 0) && + !candidateIds.has(item.id) + ) + }) +} + +function NarrativeMarkdown({ + item, + candidate = false +}: { + item: NarrativeItem + candidate?: boolean +}): React.JSX.Element { + return ( + +
+ +
+
+ ) +} + +function ProcessItems({ turn, - expanded + candidateIds }: { turn: AssistantTurn - expanded: boolean + candidateIds?: ReadonlySet }): React.JSX.Element { - const scrollRef = useRef(null) - const [following, setFollowing] = useState(true) - const running = - turn.status === 'running' || - turn.status === 'retrying' || - turn.status === 'waiting' - - useEffect(() => { - if (!expanded) return - const element = scrollRef.current - if (!element) return - if (running) { - element.scrollTop = element.scrollHeight - } else { - element.scrollTop = 0 - } - window.requestAnimationFrame(() => setFollowing(running)) - }, [expanded, running]) - - useEffect(() => { - const element = scrollRef.current - if (expanded && running && following && element) { - element.scrollTop = element.scrollHeight - } - }, [expanded, following, running, turn.items]) + return ( + <> + {processItems(turn, candidateIds).map((item) => { + if (item.kind === 'narrative') { + return item.narrative === 'reasoning' ? ( +
+ {item.text} +
+ ) : ( + + ) + } + if (item.kind === 'action') { + return ( + + ) + } + if (item.kind === 'interaction' && !item.actionId) { + return + } + return null + })} + + ) +} +function ProcessContents({ + turn, + candidateIds +}: { + turn: AssistantTurn + candidateIds?: ReadonlySet +}): React.JSX.Element { return (
{ - const element = event.currentTarget - setFollowing( - element.scrollHeight - element.scrollTop - element.clientHeight < 32 - ) - }} - ref={scrollRef} > - {running ? ( - - ) : ( - { - if (part.type === 'text') return [] - if ( - part.type === 'tool-call' && - [ - 'read', - 'grep', - 'glob', - 'find', - 'ls', - 'web_search', - 'fetch' - ].includes(part.toolName.toLowerCase()) && - !part.isError - ) { - return ['group-process', 'group-context'] as const - } - return ['group-process'] as const - }} - indicator="always" - > - {({ part, children }) => { - if (part.type === 'group-process') return <>{children} - if (part.type === 'group-context') { - return ( -
-
- - {contextSummary(turn, part.indices)} -
- {children} -
- ) - } - if (part.type === 'reasoning') { - return
{part.text}
- } - if (part.type === 'tool-call') { - const action = turn.items.find( - (item): item is ActionItem => - item.kind === 'action' && - item.toolCallId === part.toolCallId - ) - return action ? ( - - ) : null - } - if (part.type === 'data') { - if ( - part.name === 'omp-interaction' && - part.data && - typeof part.data === 'object' - ) { - const interaction = part.data as InteractionItem - return interaction.actionId ? null : ( - - ) - } - return null - } - if (part.type === 'indicator') { - return running ? ( -
- - 正在处理 -
- ) : null - } - return null - }} -
- )} +
- {!following && running && ( - - )}
) } @@ -890,7 +936,43 @@ function formatElapsed(turn: AssistantTurn, now: number): string | undefined { const elapsed = turnElapsedMs(turn, now) if (elapsed === undefined) return undefined if (elapsed < 1_000) return '少于 1 秒' - return `${Math.floor(elapsed / 1_000)} 秒` + const seconds = Math.floor(elapsed / 1_000) + if (seconds < 60) return `${seconds}秒` + const minutes = Math.floor(seconds / 60) + if (minutes < 60) return `${minutes}分${seconds % 60}秒` + return `${Math.floor(minutes / 60)}小时${minutes % 60}分` +} + +function processStatusIcon(turn: AssistantTurn): React.JSX.Element { + if (turn.status === 'running' || turn.status === 'retrying') { + return ( + + ) + } + if (turn.status === 'waiting') { + return + } + if (turn.status === 'completed' || turn.status === 'completed-incomplete') { + return + } + if (turn.status === 'error' || turn.status === 'length') { + return + } + return +} + +function processStatusLabel(turn: AssistantTurn): string { + if (turn.status === 'running' || turn.status === 'retrying') return '运行中' + if (turn.status === 'waiting') return '等待操作' + if (turn.status === 'completed' || turn.status === 'completed-incomplete') { + return '已完成' + } + if (turn.status === 'error' || turn.status === 'length') return '失败' + return '已中止' } function ProcessSummary({ @@ -926,32 +1008,44 @@ function ProcessSummary({ const approvalDeadline = Math.min( ...pendingApprovals.map((request) => request.deadline) ) - const label = + const unresolvedInteraction = turn.items.find( + (item): item is InteractionItem => + item.kind === 'interaction' && !item.resolved && !item.timedOut + ) + const waitingLabel = pendingApprovals.length > 0 - ? `等待操作 · ${Math.max( + ? `等待确认 · ${Math.max( 0, Math.ceil((approvalDeadline - now) / 1_000) - )} 秒后自动允许` - : [ - elapsed - ? running - ? `思考中 ${elapsed}` - : `思考了 ${elapsed}` - : undefined, - toolCount ? `${toolCount} 个工具` : undefined, - turnStatusText(turn.status) - ] - .filter(Boolean) - .join(' · ') + )}秒` + : unresolvedInteraction + ? unresolvedInteraction.deadline + ? `等待操作 · ${Math.max( + 0, + Math.ceil((unresolvedInteraction.deadline - now) / 1_000) + )}秒` + : '等待操作' + : turn.status === 'waiting' + ? '等待操作' + : undefined + const label = + waitingLabel ?? + [toolCount ? `${toolCount} 次工具调用` : undefined, elapsed] + .filter(Boolean) + .join(' · ') return ( ) @@ -984,11 +1078,7 @@ function AssistantMessage(): React.JSX.Element | null { (item): item is ArtifactItem => item.kind === 'artifact' && item.artifact === 'command-result' ) - const hasProcess = turn.items.some( - (item) => - item.kind !== 'artifact' && - (item.kind !== 'narrative' || item.narrative !== 'final') - ) + const hasProcess = processItems(turn).length > 0 const finalText = turn.finalItemIds .map((id) => turn.items.find((item) => item.id === id)) .flatMap((item) => @@ -1017,13 +1107,11 @@ function AssistantMessage(): React.JSX.Element | null { )} - {hasProcess && expanded && ( - - )} + {hasProcess && expanded && } {commandResults.map((item) => ( ))} -
+
( @@ -1031,6 +1119,7 @@ function AssistantMessage(): React.JSX.Element | null { components={markdownComponents} defer skipHtml + smooth={false} /> ), Reasoning: () => null, @@ -1116,12 +1205,11 @@ function LiveAssistantTurn({ (item): item is ArtifactItem => item.kind === 'artifact' && item.artifact === 'command-result' ) - const hasProcess = turn.items.some( - (item) => - item.kind !== 'artifact' && - (item.kind !== 'narrative' || item.narrative !== 'final') - ) - if (!hasProcess && commandResults.length > 0) { + const candidates = answerCandidateItems(turn) + const candidateIds = new Set(candidates.map((item) => item.id)) + const hasProcess = processItems(turn, candidateIds).length > 0 + const hasSummary = hasProcess || toolApprovals.length > 0 + if (!hasSummary && candidates.length === 0 && commandResults.length > 0) { return (
- - setProjection((current) => - setTurnCollapsed(current, turn.id, expanded) - ) - } - turn={turn} - toolApprovals={toolApprovals} - /> - {expanded && ( + {hasSummary && ( + + setProjection((current) => + setTurnCollapsed(current, turn.id, expanded) + ) + } + turn={turn} + toolApprovals={toolApprovals} + /> + )} + {hasSummary && expanded && ( <> - + {hasProcess && ( + + )} )} + {commandResults.map((item) => ( + + ))} + {candidates.map((item) => ( + + ))}
) } @@ -1304,6 +1402,7 @@ export function ConversationRuntime({ projection, setProjection, isRunning, + workspacePath, onSend, onCancel, children @@ -1311,6 +1410,7 @@ export function ConversationRuntime({ projection: ConversationProjection setProjection: React.Dispatch> isRunning: boolean + workspacePath?: string onSend: (message: string) => Promise onCancel: () => Promise children: ReactNode @@ -1348,7 +1448,9 @@ export function ConversationRuntime({ }) const messageKey = messages.map((message) => message.id).join('\n') return ( - + {children} diff --git a/src/renderer/omp-event-reducer.ts b/src/renderer/omp-event-reducer.ts index 29b60e1..8116538 100644 --- a/src/renderer/omp-event-reducer.ts +++ b/src/renderer/omp-event-reducer.ts @@ -17,6 +17,7 @@ export type NarrativeItem = { text: string messageId: string blockIndex: number + redacted?: boolean } export type ActionCategory = @@ -366,7 +367,8 @@ function itemsFromMessage( narrative: 'reasoning', text: '思考内容不可用', messageId: messageIdValue, - blockIndex + blockIndex, + redacted: true } ] } @@ -986,11 +988,7 @@ export function turnElapsedMs( ): number | undefined { if (turn.startedAt === undefined) return undefined const end = turn.endedAt ?? now - const activeWait = - turn.waitingStartedAt === undefined - ? 0 - : Math.max(0, now - turn.waitingStartedAt) - return Math.max(0, end - turn.startedAt - turn.waitingDurationMs - activeWait) + return Math.max(0, end - turn.startedAt) } export function shouldCollapseTurn(turn: AssistantTurn): boolean { diff --git a/src/renderer/styles.css b/src/renderer/styles.css index bdb27b8..210d3bb 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -1,4 +1,5 @@ @import 'tailwindcss'; +@plugin '@tailwindcss/typography'; :root { color-scheme: light; @@ -91,8 +92,12 @@ body { contain-intrinsic-size: auto 5rem; } -.assistant-final { +.assistant-final, +.assistant-answer-candidate { margin-top: 0.85rem; + color: var(--text-primary); + font-size: 0.875rem; + line-height: 1.75; } .assistant-copy-row { @@ -101,27 +106,33 @@ body { margin-top: 0.45rem; } -.assistant-final:empty { +.assistant-final:empty, +.assistant-answer-candidate:empty { display: none; } -.assistant-final p { +.assistant-final p, +.assistant-answer-candidate p { margin: 0.55rem 0; } .assistant-final ul, -.assistant-final ol { +.assistant-final ol, +.assistant-answer-candidate ul, +.assistant-answer-candidate ol { margin: 0.65rem 0; padding-left: 1.4rem; } -.assistant-final a { +.assistant-final a, +.assistant-answer-candidate a { color: #3c5d91; text-decoration: underline; text-underline-offset: 2px; } -.assistant-final pre { +.assistant-final pre, +.assistant-answer-candidate pre { overflow-x: auto; border: 1px solid var(--border-subtle); border-radius: 0.65rem; @@ -129,12 +140,74 @@ body { padding: 0.75rem; font-size: 0.78rem; line-height: 1.6; + white-space: pre; +} + +.assistant-final h1, +.assistant-answer-candidate h1 { + font-size: 20px; + font-weight: 650; +} + +.assistant-final h2, +.assistant-answer-candidate h2 { + font-size: 18px; + font-weight: 650; +} + +.assistant-final h3, +.assistant-answer-candidate h3 { + font-size: 16px; + font-weight: 600; +} + +.assistant-final h4, +.assistant-answer-candidate h4 { + font-size: 14px; + font-weight: 600; +} + +.assistant-final h5, +.assistant-answer-candidate h5 { + color: var(--text-secondary); + font-size: 14px; + font-weight: 600; +} + +.assistant-final h6, +.assistant-answer-candidate h6 { + color: var(--text-secondary); + font-size: 12px; + font-weight: 600; +} + +.assistant-final blockquote, +.assistant-answer-candidate blockquote { + border-left: 2px solid var(--border); + font-style: normal; +} + +.assistant-final :not(pre) > code, +.assistant-answer-candidate :not(pre) > code { + border: 0; + border-radius: 0.3rem; + background: #f1f1ee; + padding: 0.1rem 0.25rem; + font-size: 12px; + font-weight: 400; +} + +.assistant-final :not(pre) > code::before, +.assistant-final :not(pre) > code::after, +.assistant-answer-candidate :not(pre) > code::before, +.assistant-answer-candidate :not(pre) > code::after { + content: none; } .process-summary { display: flex; - width: 100%; - min-height: 2.45rem; + width: min(100%, 32rem); + min-height: 2.25rem; align-items: center; justify-content: space-between; gap: 0.75rem; @@ -148,13 +221,25 @@ body { text-align: left; } +.process-summary-main { + display: inline-flex; + min-width: 0; + align-items: center; + gap: 0.45rem; +} + +.process-summary-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .process-summary:hover { border-color: var(--border); background: #f6f6f3; } .process-summary:focus-visible, -.process-scroll-bottom:focus-visible, .thread-scroll-bottom:focus-visible, .tool-copy:focus-visible { outline: 2px solid #696963; @@ -167,38 +252,40 @@ body { } .process-content { - max-height: min(60vh, 640px); - overflow-y: auto; - overscroll-behavior: auto; border-left: 1px solid var(--border-subtle); padding: 0.35rem 0 0.35rem 0.8rem; color: var(--text-secondary); - scrollbar-gutter: stable; } -.process-narrative { +.thinking-narrative { margin: 0.3rem 0; - color: var(--text-secondary); - font-size: 0.79rem; + color: var(--text-muted); + font-size: 0.75rem; line-height: 1.65; white-space: pre-wrap; } -.process-indicator, -.context-heading { - display: flex; - align-items: center; - gap: 0.4rem; - color: var(--text-muted); - font-size: 0.75rem; +.process-narrative-markdown { + margin: 0.3rem 0; + color: var(--text-secondary); + font-size: 0.8125rem; + line-height: 1.6; } -.context-group { +.process-narrative-markdown :is(p, ul, ol, pre, blockquote) { margin: 0.35rem 0; } -.context-heading { - margin-bottom: 0.2rem; +.process-narrative-markdown :is(h1, h2, h3, h4, h5, h6) { + margin: 0.45rem 0 0.25rem; + color: var(--text-primary); + font-size: inherit; + font-weight: 600; +} + +.process-narrative-markdown pre { + overflow-x: auto; + white-space: pre; } .tool-row { @@ -213,6 +300,14 @@ body { line-height: 1.35; } +.tool-row-subagent { + margin: 0.2rem 0; +} + +.tool-row-subagent .tool-kind { + color: #53657d; +} + .tool-name { color: var(--text-primary); font-weight: 500; @@ -238,10 +333,33 @@ body { place-items: center; border-radius: 0.35rem; color: var(--text-muted); + opacity: 0; } -.tool-copy:hover { +.tool-copy:hover, +.tool-row:hover .tool-copy, +.tool-row:focus-within .tool-copy, +.tool-row-error .tool-copy { background: var(--surface-selected); + opacity: 1; +} + +.tool-result-summary, +.tool-error-summary { + grid-column: 2 / -1; + min-width: 0; + overflow: hidden; + color: var(--text-muted); + text-overflow: ellipsis; + white-space: nowrap; +} + +.tool-error-summary { + display: -webkit-box; + color: #b42318; + white-space: normal; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; } .message-copy { @@ -349,7 +467,6 @@ body { resize: vertical; } -.process-scroll-bottom, .thread-scroll-bottom { position: sticky; z-index: 5; @@ -364,12 +481,6 @@ body { box-shadow: 0 3px 10px rgb(0 0 0 / 8%); } -.process-scroll-bottom { - right: 0.5rem; - bottom: 0.5rem; - margin: -2.5rem 0.5rem 0 auto; -} - .tool-approval-panel { margin-top: 0.75rem; overflow: hidden; @@ -462,6 +573,13 @@ body { visibility: hidden; } +@media (prefers-reduced-motion: reduce) { + .tool-spinner, + .process-spinner { + animation: none !important; + } +} + button, input, textarea { diff --git a/tests/renderer/conversation-thread.test.tsx b/tests/renderer/conversation-thread.test.tsx index 193ad51..0ae32e3 100644 --- a/tests/renderer/conversation-thread.test.tsx +++ b/tests/renderer/conversation-thread.test.tsx @@ -24,10 +24,12 @@ function projectionFrom( function Harness({ initial, - toolApprovals + toolApprovals, + workspacePath }: { initial: ConversationProjection toolApprovals?: ToolApprovalRequest[] + workspacePath?: string }): React.JSX.Element { const [projection, setProjection] = useState(initial) return ( @@ -38,6 +40,7 @@ function Harness({ onSend={async () => undefined} projection={projection} setProjection={setProjection} + workspacePath={workspacePath} > @@ -202,10 +205,10 @@ describe('ConversationThread', () => { }, { type: 'agent_end' } ]) - render() + const { container } = render() const summary = await screen.findByRole('button', { - name: /思考了 4 秒 · 1 个工具 · 已完成/ + name: /已完成 · 1 次工具调用 · 4秒/ }) expect(summary).toHaveAttribute('aria-expanded', 'false') expect(screen.queryByText('检查代码')).not.toBeInTheDocument() @@ -216,6 +219,7 @@ describe('ConversationThread', () => { expect(screen.getByText('检查代码')).toBeInTheDocument() expect(screen.getByText('先读取文件。')).toBeInTheDocument() expect(screen.getByText('src/app.tsx')).toBeInTheDocument() + expect(container.querySelector('.context-group')).toBeNull() expect(screen.queryByText(/展开全文|查看详情/)).not.toBeInTheDocument() }) @@ -279,6 +283,320 @@ describe('ConversationThread', () => { expect(screen.getByText('命令退出码为 1')).toBeInTheDocument() }) + it('活动 Turn 的尾部普通文本显示为回答候选,且不显示 Process 摘要和复制按钮', async () => { + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_update', + message: { + id: 'a1', + role: 'assistant', + content: [{ type: 'text', text: '## 正在整理\n\n候选回答' }] + } + } + ]) + const { container } = render() + + expect( + await screen.findByRole('heading', { name: '正在整理' }) + ).toBeVisible() + expect(screen.getByText('候选回答')).toBeVisible() + expect( + container.querySelector('.assistant-answer-candidate') + ).not.toBeNull() + expect(container.querySelector('.process-summary')).toBeNull() + expect(screen.queryByRole('button', { name: '复制回答' })).toBeNull() + }) + + it('新的工具项到来后,原回答候选回退到 Process', async () => { + function CandidateFallbackHarness(): React.JSX.Element { + const [projection, setProjection] = useState(() => + projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_update', + message: { + id: 'a1', + role: 'assistant', + content: [{ type: 'text', text: '我先给出判断。' }] + } + } + ]) + ) + return ( +
+ + undefined} + onSend={async () => undefined} + projection={projection} + setProjection={setProjection} + > + + +
+ ) + } + + const { container } = render() + expect(await screen.findByText('我先给出判断。')).toBeVisible() + expect( + container.querySelector('.assistant-answer-candidate') + ).not.toBeNull() + + fireEvent.click(screen.getByRole('button', { name: '添加工具' })) + + await waitFor(() => + expect(container.querySelector('.assistant-answer-candidate')).toBeNull() + ) + expect(screen.getByLabelText('完整执行过程')).toHaveTextContent( + '我先给出判断。' + ) + expect(screen.getByLabelText('完整执行过程')).toHaveTextContent('读取') + }) + + it('工具逐条显示,不生成 Context Group,并缩短工作区内路径', async () => { + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_update', + message: { + id: 'a1', + role: 'assistant', + content: [ + { + type: 'toolCall', + id: 't1', + name: 'read', + arguments: { path: '/workspace/project/src/app.tsx' } + }, + { + type: 'toolCall', + id: 't2', + name: 'grep', + arguments: { pattern: 'ConversationRuntime' } + } + ] + } + } + ]) + const { container } = render( + + ) + + expect(await screen.findByText('src/app.tsx')).toBeVisible() + expect(screen.getByText('ConversationRuntime')).toBeVisible() + expect(container.querySelectorAll('.tool-row')).toHaveLength(2) + expect(container.querySelector('.context-group')).toBeNull() + }) + + it('隐藏 redacted thinking,子任务只显示一行清理后的结果摘要', async () => { + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_end', + message: { + id: 'a1', + role: 'assistant', + stopReason: 'toolUse', + content: [ + { type: 'redactedThinking' }, + { + type: 'toolCall', + id: 't1', + name: 'task', + arguments: { tasks: [{ name: 'A' }, { name: 'B' }] } + } + ] + } + }, + { + type: 'tool_execution_end', + toolCallId: 't1', + toolName: 'task', + result: { summary: '**完成** [报告](https://example.com)' } + } + ]) + render() + + expect(await screen.findByText('2 个任务')).toBeVisible() + expect(screen.getByText('完成 报告')).toBeVisible() + expect(screen.queryByText('思考内容不可用')).toBeNull() + }) + + it('空文本不打断候选,Thinking 保持在 Process', async () => { + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_update', + message: { + id: 'a1', + role: 'assistant', + content: [ + { type: 'thinking', thinking: '内部检查' }, + { type: 'text', text: '可见候选' }, + { type: 'text', text: ' ' } + ] + } + } + ]) + const { container } = render() + + expect(await screen.findByText('可见候选')).toBeVisible() + expect( + container.querySelector('.assistant-answer-candidate') + ).toHaveTextContent('可见候选') + expect(screen.getByLabelText('完整执行过程')).toHaveTextContent('内部检查') + expect(container.querySelector('.thinking-narrative')).toHaveTextContent( + '内部检查' + ) + }) + + it('Command、Edit、External 和三个 Subagent 工具使用各自展示分支', async () => { + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_update', + message: { + id: 'a1', + role: 'assistant', + content: [ + { + type: 'toolCall', + id: 'cmd', + name: 'bash', + arguments: { command: 'pnpm test\necho done' } + }, + { + type: 'toolCall', + id: 'edit', + name: 'apply_patch', + arguments: { path: '/workspace/project/src/app.tsx' } + }, + { type: 'toolCall', id: 'external', name: 'custom_tool' }, + { type: 'toolCall', id: 'task', name: 'task' }, + { type: 'toolCall', id: 'subagent', name: 'subagent' }, + { type: 'toolCall', id: 'delegate', name: 'delegate' } + ] + } + } + ]) + const { container } = render( + + ) + + expect(await screen.findByText('pnpm test')).toBeVisible() + expect(screen.getByText('应用修改')).toBeVisible() + expect(screen.getByText('src/app.tsx')).toBeVisible() + expect(screen.getByText('custom_tool')).toBeVisible() + expect(screen.getAllByText('子任务')).toHaveLength(3) + expect(container.querySelectorAll('.tool-row-subagent')).toHaveLength(3) + }) + + it('失败结束时回答候选回到 Process,不留在回答区域', async () => { + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_end', + message: { + id: 'a1', + role: 'assistant', + stopReason: 'error', + content: [{ type: 'text', text: '未完成的回答' }] + } + }, + { type: 'agent_end' } + ]) + const { container } = render() + + expect(await screen.findByRole('button', { name: /失败/ })).toHaveAttribute( + 'aria-expanded', + 'true' + ) + expect(screen.getByLabelText('完整执行过程')).toHaveTextContent( + '未完成的回答' + ) + expect(container.querySelector('.assistant-answer-candidate')).toBeNull() + expect(container.querySelector('.assistant-final')).toBeEmptyDOMElement() + }) + + it('completed-incomplete 按完成显示,不显示诊断文案', async () => { + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_end', + message: { + id: 'a1', + role: 'assistant', + stopReason: 'stop', + content: [ + { type: 'toolCall', id: 't1', name: 'read' }, + { type: 'text', text: '可用回答' } + ] + } + }, + { type: 'agent_end' } + ]) + render() + + const summary = await screen.findByRole('button', { name: /已完成/ }) + expect(summary).toHaveAttribute('aria-expanded', 'false') + expect(screen.queryByText(/记录不完整|状态未知/)).toBeNull() + expect(screen.getByText('可用回答')).toBeVisible() + }) + + it('等待确认摘要隐藏工具数量和总时长', async () => { + const deadline = Date.now() + 30_000 + const projection = projectionFrom([ + { type: 'agent_start' }, + { + type: 'message_update', + message: { + id: 'a1', + role: 'assistant', + content: [{ type: 'toolCall', id: 't1', name: 'bash' }] + } + } + ]) + render( + + ) + + const summary = await screen.findByRole('button', { name: /等待确认/ }) + expect(summary).toHaveTextContent(/等待确认 · \d+秒/) + expect(summary).not.toHaveTextContent('次工具调用') + }) + it('Markdown 不执行原始 HTML、危险链接或远程图片', async () => { const projection = projectionFrom([ { type: 'agent_start' }, diff --git a/tests/renderer/omp-event-performance.test.tsx b/tests/renderer/omp-event-performance.test.tsx index bc31291..3f84cd9 100644 --- a/tests/renderer/omp-event-performance.test.tsx +++ b/tests/renderer/omp-event-performance.test.tsx @@ -155,9 +155,9 @@ describe('流式投影性能', () => { }) }) // React 提交时已经更新 DOM。文字断言只检查结果,不计入性能数据。 - expect(container.querySelector('.process-content')).toHaveTextContent( - `可见流式输出 ${second * 100 + 99}` - ) + expect( + container.querySelector('.assistant-answer-candidate') + ).toHaveTextContent(`可见流式输出 ${second * 100 + 99}`) } const commitP95 = commitLatencies.sort((left, right) => left - right)[ diff --git a/tests/renderer/omp-event-reducer.test.ts b/tests/renderer/omp-event-reducer.test.ts index 4ee86fc..800a711 100644 --- a/tests/renderer/omp-event-reducer.test.ts +++ b/tests/renderer/omp-event-reducer.test.ts @@ -306,7 +306,7 @@ describe('OmpEventReducer', () => { expect(shouldCollapseTurn(turn)).toBe(false) }) - it('摘要耗时扣除 Interaction 等待时间', () => { + it('摘要耗时使用 Agent Turn 的完整起止时间', () => { const projection = run([ { type: 'agent_start' }, { @@ -328,7 +328,7 @@ describe('OmpEventReducer', () => { { type: 'agent_end' } ]) const turn = assistantTurn(projection) - expect(turnElapsedMs(turn)).toBe(300) + expect(turnElapsedMs(turn)).toBe(400) }) it('历史按可见用户消息分 Turn,隐藏用户消息不切断 Turn', () => {