Repository navigation
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
嘿——我发现了 5 个问题
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src-tauri/src/commands/file_ops.rs" line_range="669-670" />
<code_context>
+ // Screencap 的自定义 filename 可包含子目录;只收集其目录内的 PNG / JPEG,
+ // 保留相对路径,避免不同子目录中的同名截图互相覆盖。
+ let mut screencap_images =
+ collect_files_recursively(&debug_dir.join("screencap"), "screencap")?;
+ screencap_images.retain(|entry| is_image_file(&entry.source_path));
+ screencap_images.sort_by_cached_key(|entry| {
+ std::cmp::Reverse(entry.source_path.metadata().and_then(|m| m.modified()).ok())
</code_context>
<issue_to_address>
**Export contains traversal entries**
When a task or resource author supplies a Screencap filename containing backslash-separated `..` components on Unix, where backslashes are valid filename characters, `collect_files_recursively` passes the relative filename through `normalize_archive_path`, which turns backslashes into `/` without rejecting `..`; `add_file_to_zip` then writes that name directly. An unsafe extractor can write the screenshot outside its extraction directory.
Reject parent-directory components in archive names after normalization, or construct the ZIP name from validated path components that cannot contain separators or `..`.
</issue_to_address>
### Comment 2
<location path="src-tauri/src/commands/file_ops.rs" line_range="669" />
<code_context>
+ // Screencap 的自定义 filename 可包含子目录;只收集其目录内的 PNG / JPEG,
+ // 保留相对路径,避免不同子目录中的同名截图互相覆盖。
+ let mut screencap_images =
+ collect_files_recursively(&debug_dir.join("screencap"), "screencap")?;
+ screencap_images.retain(|entry| is_image_file(&entry.source_path));
+ screencap_images.sort_by_cached_key(|entry| {
</code_context>
<issue_to_address>
**External screenshots leak or exports hang**
When a file or directory symlink exists under `debug/screencap`, `collect_files_recursively` follows symlinks, so external images enter the archive and a link back to an ancestor makes traversal repeat indefinitely; users receive private outside images or an export that never completes.
Make `collect_files_recursively` skip symlinks instead of following them.
</issue_to_address>
### Comment 3
<location path="src-tauri/src/commands/file_ops.rs" line_range="669" />
<code_context>
+ // Screencap 的自定义 filename 可包含子目录;只收集其目录内的 PNG / JPEG,
+ // 保留相对路径,避免不同子目录中的同名截图互相覆盖。
+ let mut screencap_images =
+ collect_files_recursively(&debug_dir.join("screencap"), "screencap")?;
+ screencap_images.retain(|entry| is_image_file(&entry.source_path));
+ screencap_images.sort_by_cached_key(|entry| {
</code_context>
<issue_to_address>
**Unreadable folders abort exports**
When a `debug/screencap` directory or nested directory cannot be read, `collect_files_recursively` propagates the `read_dir` error through `?`, so `export_logs_blocking` returns without producing a ZIP even when other logs are readable, leaving the created export directory behind.
Handle Screencap traversal errors locally and continue collecting readable entries instead of propagating them out of `export_logs_blocking`.
</issue_to_address>
### Comment 4
<location path="src-tauri/src/commands/file_ops.rs" line_range="681" />
<code_context>
all_entries.extend(regular_entries);
all_entries.extend(on_error_images);
all_entries.extend(vision_images);
+ all_entries.extend(screencap_images);
let total_entries = all_entries.len();
</code_context>
<issue_to_address>
**Cleared screenshots reappear in exports**
When the user clears logs manually or through auto-clear, then exports logs again, `clear_log_dirs` and `clear_log_files` leave `debug/screencap` intact, while `export_logs_blocking` includes its images, so users see old screenshots in a later export.
Clear the `debug/screencap` images as part of the log-clearing paths.
</issue_to_address>
### Comment 5
<location path="src-tauri/src/commands/file_ops.rs" line_range="681" />
<code_context>
all_entries.extend(regular_entries);
all_entries.extend(on_error_images);
all_entries.extend(vision_images);
+ all_entries.extend(screencap_images);
let total_entries = all_entries.len();
</code_context>
<issue_to_address>
**Newest screenshots land in later volumes**
When older `on_error` or `vision` images precede a newer Screencap image and the export spans multiple volumes, `export_logs_blocking` appends `screencap_images` after the other image groups, and the volume writer consumes that order, so older images can fill an earlier volume before the newer screenshot is reached.
Order the image entries together by modification time before passing them to the volume writer.
</issue_to_address>关联问题
#391 [feat] 节点动作类型Screencap的截图跟随日志导出 · 1 项要求中已满足 1 项
| # | 要求 | 状态 | 备注 |
|---|---|---|---|
| 1 | 将 debug/screencap 中 Screencap 动作保存的截图随日志导出打包。 | ✅ 已满足 | 递归收集 screencap 目录内的 PNG/JPG/JPEG,并以 screencap/ 下的相对路径写入现有导出条目。 |
Original comment in English
Hey - I've found 5 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src-tauri/src/commands/file_ops.rs" line_range="669-670" />
<code_context>
+ // Screencap 的自定义 filename 可包含子目录;只收集其目录内的 PNG / JPEG,
+ // 保留相对路径,避免不同子目录中的同名截图互相覆盖。
+ let mut screencap_images =
+ collect_files_recursively(&debug_dir.join("screencap"), "screencap")?;
+ screencap_images.retain(|entry| is_image_file(&entry.source_path));
+ screencap_images.sort_by_cached_key(|entry| {
+ std::cmp::Reverse(entry.source_path.metadata().and_then(|m| m.modified()).ok())
</code_context>
<issue_to_address>
**Export contains traversal entries**
When a task or resource author supplies a Screencap filename containing backslash-separated `..` components on Unix, where backslashes are valid filename characters, `collect_files_recursively` passes the relative filename through `normalize_archive_path`, which turns backslashes into `/` without rejecting `..`; `add_file_to_zip` then writes that name directly. An unsafe extractor can write the screenshot outside its extraction directory.
Reject parent-directory components in archive names after normalization, or construct the ZIP name from validated path components that cannot contain separators or `..`.
</issue_to_address>
### Comment 2
<location path="src-tauri/src/commands/file_ops.rs" line_range="669" />
<code_context>
+ // Screencap 的自定义 filename 可包含子目录;只收集其目录内的 PNG / JPEG,
+ // 保留相对路径,避免不同子目录中的同名截图互相覆盖。
+ let mut screencap_images =
+ collect_files_recursively(&debug_dir.join("screencap"), "screencap")?;
+ screencap_images.retain(|entry| is_image_file(&entry.source_path));
+ screencap_images.sort_by_cached_key(|entry| {
</code_context>
<issue_to_address>
**External screenshots leak or exports hang**
When a file or directory symlink exists under `debug/screencap`, `collect_files_recursively` follows symlinks, so external images enter the archive and a link back to an ancestor makes traversal repeat indefinitely; users receive private outside images or an export that never completes.
Make `collect_files_recursively` skip symlinks instead of following them.
</issue_to_address>
### Comment 3
<location path="src-tauri/src/commands/file_ops.rs" line_range="669" />
<code_context>
+ // Screencap 的自定义 filename 可包含子目录;只收集其目录内的 PNG / JPEG,
+ // 保留相对路径,避免不同子目录中的同名截图互相覆盖。
+ let mut screencap_images =
+ collect_files_recursively(&debug_dir.join("screencap"), "screencap")?;
+ screencap_images.retain(|entry| is_image_file(&entry.source_path));
+ screencap_images.sort_by_cached_key(|entry| {
</code_context>
<issue_to_address>
**Unreadable folders abort exports**
When a `debug/screencap` directory or nested directory cannot be read, `collect_files_recursively` propagates the `read_dir` error through `?`, so `export_logs_blocking` returns without producing a ZIP even when other logs are readable, leaving the created export directory behind.
Handle Screencap traversal errors locally and continue collecting readable entries instead of propagating them out of `export_logs_blocking`.
</issue_to_address>
### Comment 4
<location path="src-tauri/src/commands/file_ops.rs" line_range="681" />
<code_context>
all_entries.extend(regular_entries);
all_entries.extend(on_error_images);
all_entries.extend(vision_images);
+ all_entries.extend(screencap_images);
let total_entries = all_entries.len();
</code_context>
<issue_to_address>
**Cleared screenshots reappear in exports**
When the user clears logs manually or through auto-clear, then exports logs again, `clear_log_dirs` and `clear_log_files` leave `debug/screencap` intact, while `export_logs_blocking` includes its images, so users see old screenshots in a later export.
Clear the `debug/screencap` images as part of the log-clearing paths.
</issue_to_address>
### Comment 5
<location path="src-tauri/src/commands/file_ops.rs" line_range="681" />
<code_context>
all_entries.extend(regular_entries);
all_entries.extend(on_error_images);
all_entries.extend(vision_images);
+ all_entries.extend(screencap_images);
let total_entries = all_entries.len();
</code_context>
<issue_to_address>
**Newest screenshots land in later volumes**
When older `on_error` or `vision` images precede a newer Screencap image and the export spans multiple volumes, `export_logs_blocking` appends `screencap_images` after the other image groups, and the volume writer consumes that order, so older images can fill an earlier volume before the newer screenshot is reached.
Order the image entries together by modification time before passing them to the volume writer.
</issue_to_address>Linked issues
#391 [feat] 节点动作类型Screencap的截图跟随日志导出 · 1 of 1 met
| # | Requirement | Status | Notes |
|---|---|---|---|
| 1 | 将 debug/screencap 中 Screencap 动作保存的截图随日志导出打包。 | ✅ Met | 递归收集 screencap 目录内的 PNG/JPG/JPEG,并以 screencap/ 下的相对路径写入现有导出条目。 |
执行“导出日志”时,将
debug/screencap中的 PNG/JPG/JPEG 一并打包,递归保留截图子目录。截图组按修改时间新到旧排序,追加在既有 regular → on_error → vision 之后,保留原导出优先级。归档名称按原生路径组件构造,对字面反斜杠、百分号、冒号及非 UTF-8 名称作可逆编码,避免
a\\b.png与a/b.png等不同源文件发生 ZIP 名称碰撞。遍历跳过静态文件/目录符号链接和特殊文件。继续使用原来的 24,500,000 字节常规分卷预算、单个超大文件独占一卷和最近 10 次导出保留规则;文本脱敏流程不变。日志清理范围仍只有原有的 on_error、vision 调试产物,不增加截图清理,不涉及更新、回滚或停止重启。
验证与长期回归:
src-tauri/src/commands/file_ops.rs的 tests 模块,直接调用生产export_logs_from_dir并读取 ZIP 校验路径、条目数量和内容,不依赖临时 harness。cargo test --manifest-path src-tauri/Cargo.toml --locked --lib commands::file_ops::tests。覆盖缺失目录、截图独立导出、嵌套/Unicode 路径、反斜杠及非 UTF-8 名称碰撞、101 张截图、分卷和超大文件、保留/清理范围、文本脱敏、链接/特殊文件、不可读及删除文件。cargo check --manifest-path src-tauri/Cargo.toml --tests --locked通过。pnpm build通过;有既有 chunk 大小和动态/静态 import 提示。cargo build --manifest-path src-tauri/Cargo.toml --locked --bin mxu通过,实际 Linux 应用mxu --help退出码 0。git diff --check通过。验证边界:
Closes #391.
AI 使用信息:
Sourcery 摘要
扩展日志导出功能,将安全归档的屏幕截图纳入导出内容,同时不改变现有的导出优先级或生命周期规则。
新功能:
错误修复:
改进:
测试:
Original summary in English
Summary by Sourcery
Extend log export to include safely archived screencap images without changing existing export priorities or lifecycle rules.
New Features:
Bug Fixes:
Enhancements:
Tests: